Kea 3.3.0
ctrl_dhcp6_srv.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2026 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>
18#include <dhcp/libdhcp++.h>
20#include <dhcp6/dhcp6_log.h>
21#include <dhcp6/dhcp6to4_ipc.h>
26#include <dhcpsrv/cfgmgr.h>
27#include <dhcpsrv/db_type.h>
28#include <dhcpsrv/host_mgr.h>
32#include <hooks/hooks.h>
33#include <hooks/hooks_manager.h>
35#include <stats/stats_mgr.h>
36#include <util/encode/encode.h>
38
39#include <signal.h>
40
41#include <sstream>
42
43using namespace isc::asiolink;
44using namespace isc::config;
45using namespace isc::data;
46using namespace isc::db;
47using namespace isc::dhcp;
48using namespace isc::hooks;
49using namespace isc::stats;
50using namespace isc::util;
51using namespace std;
52namespace ph = std::placeholders;
53
54namespace {
55
57struct CtrlDhcp6Hooks {
58 int hooks_index_dhcp6_srv_configured_;
59
61 CtrlDhcp6Hooks() {
62 hooks_index_dhcp6_srv_configured_ = HooksManager::registerHook("dhcp6_srv_configured");
63 }
64
65};
66
67// Declare a Hooks object. As this is outside any function or method, it
68// will be instantiated (and the constructor run) when the module is loaded.
69// As a result, the hook indexes will be defined before any method in this
70// module is called.
71CtrlDhcp6Hooks Hooks;
72
73// Name of the file holding server identifier.
74static const char* SERVER_DUID_FILE = "kea-dhcp6-serverid";
75
85void signalHandler(int signo) {
86 // SIGHUP signals a request to reconfigure the server.
87 if (signo == SIGHUP) {
89 } else if ((signo == SIGTERM) || (signo == SIGINT)) {
91 }
92}
93
94}
95
96namespace isc {
97namespace dhcp {
98
99ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = 0;
100
101void
102ControlledDhcpv6Srv::init(const std::string& file_name) {
103 // Keep the call timestamp.
104 start_ = boost::posix_time::second_clock::universal_time();
105
106 // Configure the server using JSON file.
107 ConstElementPtr result = loadConfigFile(file_name);
108
109 int rcode;
110 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
111 if (rcode != CONTROL_RESULT_SUCCESS) {
112 string reason = comment ? comment->stringValue() :
113 "no details available";
114 isc_throw(isc::BadValue, reason);
115 }
116
117 // Set signal handlers. When the SIGHUP is received by the process
118 // the server reconfiguration will be triggered. When SIGTERM or
119 // SIGINT will be received, the server will start shutting down.
120 signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
121
122 signal_set_->add(SIGINT);
123 signal_set_->add(SIGHUP);
124 signal_set_->add(SIGTERM);
125}
126
128 signal_set_.reset();
129 getIOService()->stopAndPoll();
130}
131
133ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
134 // This is a configuration backend implementation that reads the
135 // configuration from a JSON file.
136
139
140 // Basic sanity check: file name must not be empty.
141 try {
142 if (file_name.empty()) {
143 // Basic sanity check: file name must not be empty.
144 isc_throw(isc::BadValue, "JSON configuration file not specified."
145 " Please use -c command line option.");
146 }
147
148 // Read contents of the file and parse it as JSON
149 Parser6Context parser;
150 json = parser.parseFile(file_name, Parser6Context::PARSER_DHCP6);
151 if (!json) {
152 isc_throw(isc::BadValue, "no configuration found");
153 }
154
155 // Let's do sanity check before we call json->get() which
156 // works only for map.
157 if (json->getType() != isc::data::Element::map) {
158 isc_throw(isc::BadValue, "Configuration file is expected to be "
159 "a map, i.e., start with { and end with } and contain "
160 "at least an entry called 'Dhcp6' that itself is a map. "
161 << file_name
162 << " is a valid JSON, but its top element is not a map."
163 " Did you forget to add { } around your configuration?");
164 }
165
166 // Use parsed JSON structures to configure the server
167 result = CommandMgr::instance().processCommand(createCommand("config-set", json));
168 if (!result) {
169 // Undetermined status of the configuration. This should never
170 // happen, but as the configureDhcp6Server returns a pointer, it is
171 // theoretically possible that it will return NULL.
172 isc_throw(isc::BadValue, "undefined result of "
173 "process command \"config-set\"");
174 }
175
176 // Now check is the returned result is successful (rcode=0) or not
177 // (see @ref isc::config::parseAnswer).
178 int rcode;
179 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
180 if (rcode != CONTROL_RESULT_SUCCESS) {
181 string reason = comment ? comment->stringValue() :
182 "no details available";
183 if (rcode == CONTROL_RESULT_FATAL_ERROR) {
185 } else {
186 isc_throw(isc::BadValue, reason);
187 }
188 }
189 } catch (const isc::FatalException&) {
190 throw;
191 } catch (const std::exception& ex) {
192 // If configuration failed at any stage, we drop the staging
193 // configuration and continue to use the previous one.
195
197 .arg(file_name).arg(ex.what());
198 isc_throw(isc::BadValue, "configuration error using file '"
199 << file_name << "': " << ex.what());
200 }
201
203 .arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
204 .arg(MultiThreadingMgr::instance().getThreadPoolSize())
205 .arg(MultiThreadingMgr::instance().getPacketQueueSize());
206
207 return (result);
208}
209
210bool
214
219 return (createAnswer(CONTROL_RESULT_ERROR, "Shutdown failure."));
220 }
221
222 int exit_value = 0;
223 if (args) {
224 // @todo Should we go ahead and shutdown even if the args are invalid?
225 if (args->getType() != Element::map) {
226 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
227 }
228
229 ConstElementPtr param = args->get("exit-value");
230 if (param) {
231 if (param->getType() != Element::integer) {
233 "parameter 'exit-value' is not an integer"));
234 }
235
236 exit_value = param->intValue();
237 }
238 }
239
241 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
242}
243
246 ConstElementPtr /*args*/) {
247 if (!IfaceMgr::instance().isMainThread()) {
249 "Illegal operation executing 'config-reload' on a different thread than main thread"));
250 }
251 // Get configuration file name.
253 try {
255 auto result = loadConfigFile(file);
257 return (result);
258 } catch (const FatalException& ex) {
260 .arg(file);
261 if (Daemon::getShutdownOnFailure()) {
262 shutdownServer(EXIT_FAILURE);
263 }
265 "Config reload failed: " + string(ex.what())));
266 } catch (const std::exception& ex) {
267 // Log the unsuccessful reconfiguration. The reason for failure
268 // should be already logged. Don't rethrow an exception so as
269 // the server keeps working.
271 .arg(file);
273 "Config reload failed: " + string(ex.what())));
274 }
275}
276
279 ConstElementPtr /*args*/) {
281 string hash = BaseCommandMgr::getHash(config);
282 config->set("hash", Element::create(hash));
283
285}
286
289 ConstElementPtr /*args*/) {
291
292 string hash = BaseCommandMgr::getHash(config);
293
295 params->set("hash", Element::create(hash));
296 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
297}
298
301 ConstElementPtr args) {
302 string filename;
303
304 if (args) {
305 if (args->getType() != Element::map) {
306 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
307 }
308 ConstElementPtr filename_param = args->get("filename");
309 if (filename_param) {
310 if (filename_param->getType() != Element::string) {
312 "passed parameter 'filename' is not a string"));
313 }
314 filename = filename_param->stringValue();
315 }
316 }
317
318 if (filename.empty()) {
319 // filename parameter was not specified, so let's use whatever we remember
320 // from the command-line
321 filename = getConfigFile();
322 if (filename.empty()) {
323 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
324 "Please specify filename explicitly."));
325 }
326 } else {
327 try {
328 checkWriteConfigFile(filename);
329 } catch (const isc::Exception& ex) {
330 std::ostringstream msg;
331 msg << "not allowed to write config into " << filename
332 << ": " << ex.what();
333 return (createAnswer(CONTROL_RESULT_ERROR, msg.str()));
334 }
335 }
336
337 // Ok, it's time to write the file.
338 size_t size = 0;
339 try {
340 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
341 size = writeConfigFile(filename, cfg);
342 } catch (const isc::Exception& ex) {
343 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during config-write: ")
344 + ex.what()));
345 }
346 if (size == 0) {
347 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
348 + filename));
349 }
350
351 // Ok, it's time to return the successful response.
353 params->set("size", Element::create(static_cast<long long>(size)));
354 params->set("filename", Element::create(filename));
355
356 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
357 + filename + " successful", params));
358}
359
362 ConstElementPtr args) {
363 if (!IfaceMgr::instance().isMainThread()) {
365 "Illegal operation executing 'config-set' on a different thread than main thread"));
366 }
367 const int status_code = CONTROL_RESULT_ERROR;
368 ConstElementPtr dhcp6;
369 string message;
370
371 // Command arguments are expected to be:
372 // { "Dhcp6": { ... } }
373 if (!args) {
374 message = "Missing mandatory 'arguments' parameter.";
375 } else {
376 dhcp6 = args->get("Dhcp6");
377 if (!dhcp6) {
378 message = "Missing mandatory 'Dhcp6' parameter.";
379 } else if (dhcp6->getType() != Element::map) {
380 message = "'Dhcp6' parameter expected to be a map.";
381 }
382 }
383
384 // Check unsupported objects.
385 if (message.empty()) {
386 for (auto const& obj : args->mapValue()) {
387 const string& obj_name = obj.first;
388 if (obj_name != "Dhcp6") {
390 .arg(obj_name);
391 if (message.empty()) {
392 message = "Unsupported '" + obj_name + "' parameter";
393 } else {
394 message += " (and '" + obj_name + "')";
395 }
396 }
397 }
398 if (!message.empty()) {
399 message += ".";
400 }
401 }
402
403 if (!message.empty()) {
404 // Something is amiss with arguments, return a failure response.
405 ConstElementPtr result = isc::config::createAnswer(status_code,
406 message);
407 return (result);
408 }
409
411 (LeaseMgrFactory::instance().getType() == "memfile")) {
413 auto file_name = mgr.getLeaseFilePath(Memfile_LeaseMgr::V6);
416 "Can not update configuration while lease file cleanup process is running."));
417 }
418 }
419
420 // stop thread pool (if running)
422
423 // We are starting the configuration process so we should remove any
424 // staging configuration that has been created during previous
425 // configuration attempts.
427
428 // Parse the logger configuration explicitly into the staging config.
429 // Note this does not alter the current loggers, they remain in
430 // effect until we apply the logging config below. If no logging
431 // is supplied logging will revert to default logging.
432 Daemon::configureLogger(dhcp6, CfgMgr::instance().getStagingCfg());
433
434 // Let's apply the new logging. We do it early, so we'll be able to print
435 // out what exactly is wrong with the new config in case of problems.
436 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
437
438 // Now we configure the server proper.
439 ConstElementPtr result = processConfig(dhcp6);
440
441 // If the configuration parsed successfully, apply the new logger
442 // configuration and then commit the new configuration. We apply
443 // the logging first in case there's a configuration failure.
444 int rcode = 0;
445 isc::config::parseAnswer(rcode, result);
446 if (getShutdown() && (rcode == CONTROL_RESULT_SUCCESS)) {
447 // Do not return success when a fatal error was triggered.
449 message = "Reconfiguration triggered a fatal error: shutting down.";
450 result = isc::config::createAnswer(rcode, message);
451 }
452 if (rcode == CONTROL_RESULT_SUCCESS) {
453 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
454
455 // Use new configuration.
457 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
458 // Ok, we applied the logging from the upcoming configuration, but
459 // there were problems with the config. As such, we need to back off
460 // and revert to the previous logging configuration. This is not done if
461 // sequence == 0, because that would mean always reverting to stdout by
462 // default, and it is arguably more helpful to have the error in a
463 // potential file or syslog configured in the upcoming configuration.
464 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
465
466 if (rcode == CONTROL_RESULT_FATAL_ERROR) {
467 // Not initial configuration so someone can believe we reverted
468 // to the previous configuration. It is not the case so be clear
469 // about this.
471 }
472 }
473
475 try {
476 // Handle events registered by hooks using external IOService objects.
478 } catch (const std::exception& ex) {
479 if (rcode == CONTROL_RESULT_FATAL_ERROR) {
480 if (Daemon::getShutdownOnFailure()) {
481 shutdownServer(EXIT_FAILURE);
482 }
483 return (result);
484 }
485 std::ostringstream err;
486 err << "Error initializing hooks: "
487 << ex.what();
489 }
490
491 if (rcode == CONTROL_RESULT_FATAL_ERROR && Daemon::getShutdownOnFailure()) {
492 shutdownServer(EXIT_FAILURE);
493 }
494
495 return (result);
496}
497
500 ConstElementPtr args) {
501 if (!IfaceMgr::instance().isMainThread()) {
503 "Illegal operation executing 'config-test' on a different thread than main thread"));
504 }
505 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
506 ConstElementPtr dhcp6;
507 string message;
508
509 // Command arguments are expected to be:
510 // { "Dhcp6": { ... } }
511 if (!args) {
512 message = "Missing mandatory 'arguments' parameter.";
513 } else {
514 dhcp6 = args->get("Dhcp6");
515 if (!dhcp6) {
516 message = "Missing mandatory 'Dhcp6' parameter.";
517 } else if (dhcp6->getType() != Element::map) {
518 message = "'Dhcp6' parameter expected to be a map.";
519 }
520 }
521
522 // Check unsupported objects.
523 if (message.empty()) {
524 for (auto const& obj : args->mapValue()) {
525 const string& obj_name = obj.first;
526 if (obj_name != "Dhcp6") {
528 .arg(obj_name);
529 if (message.empty()) {
530 message = "Unsupported '" + obj_name + "' parameter";
531 } else {
532 message += " (and '" + obj_name + "')";
533 }
534 }
535 }
536 if (!message.empty()) {
537 message += ".";
538 }
539 }
540
541 if (!message.empty()) {
542 // Something is amiss with arguments, return a failure response.
543 ConstElementPtr result = isc::config::createAnswer(status_code,
544 message);
545 return (result);
546 }
547
548 // stop thread pool (if running)
550
551 // We are starting the configuration process so we should remove any
552 // staging configuration that has been created during previous
553 // configuration attempts.
555
556 // Now we check the server proper.
557 return (checkConfig(dhcp6));
558}
559
562 ConstElementPtr args) {
563 std::ostringstream message;
564 int64_t max_period = 0;
565 std::string origin;
566
567 // If the args map does not contain 'origin' parameter, the default type
568 // will be used (user command).
569 auto type = NetworkState::USER_COMMAND;
570
571 // Parse arguments to see if the 'max-period' or 'origin' parameters have
572 // been specified.
573 if (args) {
574 // Arguments must be a map.
575 if (args->getType() != Element::map) {
576 message << "arguments for the 'dhcp-disable' command must be a map";
577
578 } else {
579 ConstElementPtr max_period_element = args->get("max-period");
580 // max-period is optional.
581 if (max_period_element) {
582 // It must be an integer, if specified.
583 if (max_period_element->getType() != Element::integer) {
584 message << "'max-period' argument must be a number";
585
586 } else {
587 // It must be positive integer.
588 max_period = max_period_element->intValue();
589 if (max_period <= 0) {
590 message << "'max-period' must be positive integer";
591 }
592 }
593 }
594 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
595 // stable release. However, the 'origin' is kept for backward compatibility
596 // with Kea versions before 2.5.8. It is common to receive both parameters
597 // because HA hook library sends both in case the partner server hasn't been
598 // upgraded to the new version. The 'origin-id' takes precedence over the
599 // 'origin'.
600 ConstElementPtr origin_id_element = args->get("origin-id");
601 ConstElementPtr origin_element = args->get("origin");
602 // The 'origin-id' and 'origin' arguments are optional.
603 if (origin_id_element) {
604 if (origin_id_element->getType() == Element::integer) {
605 type = origin_id_element->intValue();
606 } else {
607 message << "'origin-id' argument must be a number";
608 }
609 } else if (origin_element) {
610 switch (origin_element->getType()) {
611 case Element::string:
612 origin = origin_element->stringValue();
613 if (origin == "ha-partner") {
615 } else if (origin != "user") {
616 if (origin.empty()) {
617 origin = "(empty string)";
618 }
619 message << "invalid value used for 'origin' parameter: "
620 << origin;
621 }
622 break;
623 case Element::integer:
624 type = origin_element->intValue();
625 break;
626 default:
627 // It must be a string or a number, if specified.
628 message << "'origin' argument must be a string or a number";
629 }
630 }
631 }
632 }
633
634 // No error occurred, so let's disable the service.
635 if (message.tellp() == 0) {
636 message << "DHCPv6 service disabled";
637 if (max_period > 0) {
638 message << " for " << max_period << " seconds";
639
640 // The user specified that the DHCP service should resume not
641 // later than in max-period seconds. If the 'dhcp-enable' command
642 // is not sent, the DHCP service will resume automatically.
643 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
644 type);
645 }
646 network_state_->disableService(type);
647
648 // Success.
649 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
650 }
651
652 // Failure.
653 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
654}
655
658 ConstElementPtr args) {
659 std::ostringstream message;
660 std::string origin;
661
662 // If the args map does not contain 'origin' parameter, the default type
663 // will be used (user command).
664 auto type = NetworkState::USER_COMMAND;
665
666 // Parse arguments to see if the 'origin' parameter has been specified.
667 if (args) {
668 // Arguments must be a map.
669 if (args->getType() != Element::map) {
670 message << "arguments for the 'dhcp-enable' command must be a map";
671
672 } else {
673 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
674 // stable release. However, the 'origin' is kept for backward compatibility
675 // with Kea versions before 2.5.8. It is common to receive both parameters
676 // because HA hook library sends both in case the partner server hasn't been
677 // upgraded to the new version. The 'origin-id' takes precedence over the
678 // 'origin'.
679 ConstElementPtr origin_id_element = args->get("origin-id");
680 ConstElementPtr origin_element = args->get("origin");
681 // The 'origin-id' and 'origin' arguments are optional.
682 if (origin_id_element) {
683 if (origin_id_element->getType() == Element::integer) {
684 type = origin_id_element->intValue();
685 } else {
686 message << "'origin-id' argument must be a number";
687 }
688 } else if (origin_element) {
689 switch (origin_element->getType()) {
690 case Element::string:
691 origin = origin_element->stringValue();
692 if (origin == "ha-partner") {
694 } else if (origin != "user") {
695 if (origin.empty()) {
696 origin = "(empty string)";
697 }
698 message << "invalid value used for 'origin' parameter: "
699 << origin;
700 }
701 break;
702 case Element::integer:
703 type = origin_element->intValue();
704 break;
705 default:
706 // It must be a string or a number, if specified.
707 message << "'origin' argument must be a string or a number";
708 }
709 }
710 }
711 }
712
713 // No error occurred, so let's enable the service.
714 if (message.tellp() == 0) {
715 network_state_->enableService(type);
716
717 // Success.
719 "DHCP service successfully enabled"));
720 }
721
722 // Failure.
723 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
724}
725
730 std::string message;
731 bool error = false;
732 try {
733 ifaces->set("interfaces", IfaceMgr::instance().ifacesToElement());
734 } catch (const std::exception& ex) {
735 error = true;
736 message = ex.what();
737 } catch (...) {
738 error = true;
739 message = "unknown error";
740 }
741
742 ostringstream msg;
743 if (!error) {
745 << " interfaces detected.";
746 return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, msg.str(), ifaces));
747 } else {
748 msg << "Unexpected error while retrieving the list of detected interfaces: " << message;
750 }
751}
752
755 ConstElementPtr args) {
756 if (!IfaceMgr::instance().isMainThread()) {
758 "Illegal operation executing 'interface-redetect' on a different thread than main thread"));
759 }
760 std::string message;
761 bool error = false;
762 try {
763 // stop thread pool (if running)
767 } catch (const std::exception& ex) {
768 error = true;
769 message = ex.what();
770 } catch (...) {
771 error = true;
772 message = "unknown error";
773 }
774
775 ostringstream msg;
776 if (!error) {
778 } else {
779 msg << "Unexpected error while retrieving the list of detected interfaces: " << message;
781 }
782}
783
786 ConstElementPtr args) {
787 if (!IfaceMgr::instance().isMainThread()) {
789 "Illegal operation executing 'interface-add' on a different thread than main thread"));
790 }
791 string message;
792 ConstElementPtr ifaces_config;
793 if (!args) {
794 message = "Missing mandatory 'arguments' parameter.";
795 } else {
796 if (args->getType() != Element::map) {
797 message = "arguments for the 'interface-add' command must be a map";
798 } else {
799 ifaces_config = args->get("interfaces");
800 if (!ifaces_config) {
801 message = "Missing mandatory 'interfaces' map parameter in 'arguments'.";
802 }
803 auto map = args->mapValue();
804 for (auto const& key : map) {
805 if (key.first != "interfaces") {
806 message = "Unsupported '" + key.first + "' map parameter in 'arguments'.";
807 break;
808 }
809 }
810 }
811 }
812
813 if (!message.empty()) {
815 }
816 if (!ifaces_config->size()) {
817 return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Interface configuration successfully updated."));
818 }
819 bool error = false;
820 try {
821 CfgIfacePtr running_cfg = CfgMgr::instance().getCurrentCfg()->getCfgIface();
823 std::set<std::string> seen;
824 auto running_ifaces = running_cfg->toElement()->get("interfaces");
825 if (running_ifaces && (running_ifaces->getType() == Element::list)) {
826 for (auto const& item : running_ifaces->listValue()) {
827 seen.insert(item->stringValue());
828 ifaces->add(item);
829 }
830 }
831 for (auto const& item : ifaces_config->listValue()) {
832 auto const& str = item->stringValue();
833 if (seen.find(str) != seen.end()) {
834 continue;
835 }
836 seen.insert(str);
837 ifaces->add(item);
838 }
839 IfacesConfigParser parser(AF_INET6, true);
840 CfgIfacePtr cfg_iface(new CfgIface());
841 parser.parseInterfacesList(cfg_iface, ifaces);
842 running_cfg->update(*cfg_iface);
843 running_cfg->triggerOpenSocketsWithRetry(AF_INET6, getServerPort());
844 } catch (const std::exception& ex) {
845 error = true;
846 message = ex.what();
847 } catch (...) {
848 error = true;
849 message = "unknown error";
850 }
851
852 ostringstream msg;
853 if (!error) {
854 if (getShutdown()) {
855 return (isc::config::createAnswer(CONTROL_RESULT_FATAL_ERROR, "Interface configuration update triggered a fatal error: shutting down."));
856 }
857 return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Interface configuration successfully updated."));
858 } else {
859 msg << "Updating used interfaces failed: " << message;
861 }
862}
863
867 ElementPtr arguments = Element::createMap();
868 arguments->set("extended", extended);
871 arguments);
872 return (answer);
873}
874
882
885 ConstElementPtr args) {
886 int status_code = CONTROL_RESULT_ERROR;
887 string message;
888
889 // args must be { "remove": <bool> }
890 if (!args) {
891 message = "Missing mandatory 'remove' parameter.";
892 } else {
893 ConstElementPtr remove_name = args->get("remove");
894 if (!remove_name) {
895 message = "Missing mandatory 'remove' parameter.";
896 } else if (remove_name->getType() != Element::boolean) {
897 message = "'remove' parameter expected to be a boolean.";
898 } else {
899 bool remove_lease = remove_name->boolValue();
900 server_->alloc_engine_->reclaimExpiredLeases6(0, 0, remove_lease);
901 status_code = 0;
902 message = "Reclamation of expired leases is complete.";
903 }
904 }
905 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
906 return (answer);
907}
908
911 ConstElementPtr args) {
912 if (!args) {
913 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
914 }
915 if (args->getType() != Element::map) {
916 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
917 }
918 SubnetSelector selector;
920 for (auto const& entry : args->mapValue()) {
921 ostringstream errmsg;
922 if (entry.first == "interface") {
923 if (entry.second->getType() != Element::string) {
924 errmsg << "'interface' entry must be a string";
925 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
926 }
927 selector.iface_name_ = entry.second->stringValue();
928 continue;
929 } if (entry.first == "interface-id") {
930 if (entry.second->getType() != Element::string) {
931 errmsg << "'interface-id' entry must be a string";
932 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
933 }
934 try {
935 string str = entry.second->stringValue();
936 vector<uint8_t> id = util::str::quotedStringToBinary(str);
937 if (id.empty()) {
939 }
940 if (id.empty()) {
941 errmsg << "'interface-id' must be not empty";
942 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
943 }
946 id));
947 continue;
948 } catch (...) {
949 errmsg << "value of 'interface-id' was not recognized";
950 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
951 }
952 } else if (entry.first == "remote") {
953 if (entry.second->getType() != Element::string) {
954 errmsg << "'remote' entry must be a string";
955 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
956 }
957 try {
958 IOAddress addr(entry.second->stringValue());
959 if (!addr.isV6()) {
960 errmsg << "bad 'remote' entry: not IPv6";
961 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
962 }
963 selector.remote_address_ = addr;
964 continue;
965 } catch (const exception& ex) {
966 errmsg << "bad 'remote' entry: " << ex.what();
967 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
968 }
969 } else if (entry.first == "link") {
970 if (entry.second->getType() != Element::string) {
971 errmsg << "'link' entry must be a string";
972 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
973 }
974 try {
975 IOAddress addr(entry.second->stringValue());
976 if (!addr.isV6()) {
977 errmsg << "bad 'link' entry: not IPv6";
978 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
979 }
980 selector.first_relay_linkaddr_ = addr;
981 continue;
982 } catch (const exception& ex) {
983 errmsg << "bad 'link' entry: " << ex.what();
984 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
985 }
986 } else if (entry.first == "classes") {
987 if (entry.second->getType() != Element::list) {
989 "'classes' entry must be a list"));
990 }
991 for (auto const& item : entry.second->listValue()) {
992 if (!item || (item->getType() != Element::string)) {
993 errmsg << "'classes' entry must be a list of strings";
994 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
995 }
996 // Skip empty client classes.
997 if (!item->stringValue().empty()) {
998 selector.client_classes_.insert(item->stringValue());
999 }
1000 }
1001 continue;
1002 } else {
1003 errmsg << "unknown entry '" << entry.first << "'";
1004 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1005 }
1006 }
1008 getCfgSubnets6()->selectSubnet(selector);
1009 if (!subnet) {
1010 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
1011 }
1012 SharedNetwork6Ptr network;
1013 subnet->getSharedNetwork(network);
1014 ostringstream msg;
1015 if (network) {
1016 msg << "selected shared network '" << network->getName()
1017 << "' starting with subnet '" << subnet->toText()
1018 << "' id " << subnet->getID();
1019 } else {
1020 msg << "selected subnet '" << subnet->toText()
1021 << "' id " << subnet->getID();
1022 }
1023 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
1024}
1025
1029 const std::string& tag =
1030 CfgMgr::instance().getCurrentCfg()->getServerTag();
1031 ElementPtr response = Element::createMap();
1032 response->set("server-tag", Element::create(tag));
1033
1034 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
1035}
1036
1040 if (!IfaceMgr::instance().isMainThread()) {
1042 "Illegal operation executing 'config-backend-pull' on a different thread than main thread"));
1043 }
1044 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
1045 if (!ctl_info) {
1046 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
1047 }
1048
1049 // stop thread pool (if running)
1051
1052 // Reschedule the periodic CB fetch.
1053 if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
1054 TimerMgr::instance()->cancel("Dhcp6CBFetchTimer");
1055 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
1056 }
1057
1058 // Code from cbFetchUpdates.
1059 // The configuration to use is the current one because this is called
1060 // after the configuration manager commit.
1061 try {
1062 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
1063 auto mode = CBControlDHCPv6::FetchMode::FETCH_UPDATE;
1064 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
1065 } catch (const std::exception& ex) {
1067 .arg(ex.what());
1069 "On demand configuration update failed: " +
1070 string(ex.what())));
1071 }
1073 "On demand configuration update successful."));
1074}
1075
1078 ConstElementPtr /*args*/) {
1079 ElementPtr status = Element::createMap();
1080 status->set("pid", Element::create(static_cast<int>(getpid())));
1081
1082 auto now = boost::posix_time::second_clock::universal_time();
1083 // Sanity check: start_ is always initialized.
1084 if (!start_.is_not_a_date_time()) {
1085 auto uptime = now - start_;
1086 status->set("uptime", Element::create(uptime.total_seconds()));
1087 }
1088
1089 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
1090 if (!last_commit.is_not_a_date_time()) {
1091 auto reload = now - last_commit;
1092 status->set("reload", Element::create(reload.total_seconds()));
1093 }
1094
1095 auto& mt_mgr = MultiThreadingMgr::instance();
1096 if (mt_mgr.getMode()) {
1097 status->set("multi-threading-enabled", Element::create(true));
1098 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
1099 MultiThreadingMgr::instance().getThreadPoolSize())));
1100 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
1101 MultiThreadingMgr::instance().getPacketQueueSize())));
1102 ElementPtr queue_stats = Element::createList();
1103 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
1104 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
1105 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
1106 status->set("packet-queue-statistics", queue_stats);
1107
1108 } else {
1109 status->set("multi-threading-enabled", Element::create(false));
1110 }
1111
1112 // Merge lease manager status.
1113 ElementPtr lm_info;
1116 }
1117 if (lm_info && (lm_info->getType() == Element::map)) {
1118 for (auto const& entry : lm_info->mapValue()) {
1119 status->set(entry.first, entry.second);
1120 }
1121 }
1122
1123 status->set("extended-info-tables", Element::create(
1124 CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->getExtendedInfoTablesEnabled()));
1125
1126 // Iterate through the interfaces and get all the errors.
1127 ElementPtr socket_errors(Element::createList());
1128 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
1129 for (std::string const& error : interface->getErrors()) {
1130 socket_errors->add(Element::create(error));
1131 }
1132 }
1133
1134 // Abstract the information from all sockets into a single status.
1135 ElementPtr sockets(Element::createMap());
1136 if (socket_errors->empty()) {
1137 sockets->set("status", Element::create("ready"));
1138 } else {
1139 ReconnectCtlPtr const reconnect_ctl(
1140 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
1141 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
1142 sockets->set("status", Element::create("retrying"));
1143 } else {
1144 sockets->set("status", Element::create("failed"));
1145 }
1146 sockets->set("errors", socket_errors);
1147 }
1148 status->set("sockets", sockets);
1149
1150 status->set("dhcp-state", network_state_->toElement());
1151
1152 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
1153}
1154
1157 ConstElementPtr args) {
1158 StatsMgr& stats_mgr = StatsMgr::instance();
1160 // Update the default parameter.
1161 long max_samples = stats_mgr.getMaxSampleCountDefault();
1162 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1163 "statistic-default-sample-count", Element::create(max_samples));
1164 return (answer);
1165}
1166
1169 ConstElementPtr args) {
1170 StatsMgr& stats_mgr = StatsMgr::instance();
1171 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleAgeAllHandler(args);
1172 // Update the default parameter.
1173 auto duration = stats_mgr.getMaxSampleAgeDefault();
1174 long max_age = toSeconds(duration);
1175 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1176 "statistic-default-sample-age", Element::create(max_age));
1177 return (answer);
1178}
1179
1183 return (LeaseMgrFactory::instance().lfcStartHandler());
1184 }
1186 "no lease backend"));
1187}
1188
1192
1193 // Allow DB reconnect on startup. The database connection parameters specify
1194 // respective details.
1196
1197 // Single stream instance used in all error clauses
1198 std::ostringstream err;
1199
1200 if (!srv) {
1201 err << "Server object not initialized, can't process config.";
1203 }
1204
1206 .arg(srv->redactConfig(config)->str());
1207
1209
1210 // Check that configuration was successful. If not, do not reopen sockets
1211 // and don't bother with DDNS stuff.
1212 try {
1213 int rcode = 0;
1214 isc::config::parseAnswer(rcode, answer);
1215 if (rcode != CONTROL_RESULT_SUCCESS) {
1216 return (answer);
1217 }
1218 } catch (const std::exception& ex) {
1219 err << "Failed to process configuration:" << ex.what();
1221 }
1222
1223 // Enable allocator initialization prior to creating lease manager.
1225
1226 // Re-open lease and host database with new parameters.
1227 try {
1229 std::bind(&ControlledDhcpv6Srv::dbLostCallback, srv, ph::_1);
1230
1232 std::bind(&ControlledDhcpv6Srv::dbRecoveredCallback, srv, ph::_1);
1233
1235 std::bind(&ControlledDhcpv6Srv::dbFailedCallback, srv, ph::_1);
1236
1237 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
1238 string params = "universe=6";
1239 if (cfg_db->getExtendedInfoTablesEnabled()) {
1240 params += " extended-info-tables=true";
1241 }
1242 cfg_db->setAppendedParameters(params);
1243 cfg_db->createManagers();
1244 // Reset counters related to connections as all managers have been recreated.
1245 srv->getNetworkState()->resetForDbConnection();
1246 srv->getNetworkState()->resetForLocalCommands();
1247 srv->getNetworkState()->resetForRemoteCommands();
1248 } catch (const std::exception& ex) {
1249 err << "Unable to open database: " << ex.what();
1251 }
1252
1253 // Regenerate server identifier if needed.
1254 try {
1255 const std::string duid_file =
1256 std::string(CfgMgr::instance().getDataDir()) + "/" +
1257 std::string(SERVER_DUID_FILE);
1258 DuidPtr duid = CfgMgr::instance().getStagingCfg()->getCfgDUID()->create(duid_file);
1259 server_->serverid_.reset(new Option(Option::V6, D6O_SERVERID, duid->getDuid()));
1260 if (duid) {
1262 .arg(duid->toText())
1263 .arg(duid_file);
1264 }
1265
1266 } catch (const std::exception& ex) {
1267 err << "unable to configure server identifier: " << ex.what();
1269 }
1270
1271 // Server will start DDNS communications if its enabled.
1272 try {
1273 srv->startD2();
1274 } catch (const std::exception& ex) {
1275 err << "Error starting DHCP_DDNS client after server reconfiguration: "
1276 << ex.what();
1278 }
1279
1280 // Setup DHCPv4-over-DHCPv6 IPC
1281 try {
1283 } catch (const std::exception& ex) {
1284 err << "error starting DHCPv4-over-DHCPv6 IPC "
1285 " after server reconfiguration: " << ex.what();
1287 }
1288
1289 // Configure DHCP packet queueing
1290 try {
1292 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
1293 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, qc)) {
1295 .arg(IfaceMgr::instance().getPacketQueue6()->getInfoStr());
1296 }
1297
1298 } catch (const std::exception& ex) {
1299 err << "Error setting packet queue controls after server reconfiguration: "
1300 << ex.what();
1302 }
1303
1304 // Configure a callback to shut down the server when the bind socket
1305 // attempts exceeded.
1307 std::bind(&ControlledDhcpv6Srv::openSocketsFailedCallback, srv, ph::_1);
1308
1309 // Configuration may change active interfaces. Therefore, we have to reopen
1310 // sockets according to new configuration. It is possible that this
1311 // operation will fail for some interfaces but the openSockets function
1312 // guards against exceptions and invokes a callback function to
1313 // log warnings. Since we allow that this fails for some interfaces there
1314 // is no need to rollback configuration if socket fails to open on any
1315 // of the interfaces.
1316 CfgMgr::instance().getStagingCfg()->getCfgIface()->
1317 openSockets(AF_INET6, srv->getServerPort());
1318
1319 // Install the timers for handling leases reclamation.
1320 try {
1321 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
1322 setupTimers(&ControlledDhcpv6Srv::reclaimExpiredLeases,
1323 &ControlledDhcpv6Srv::deleteExpiredReclaimedLeases,
1324 server_);
1325
1326 } catch (const std::exception& ex) {
1327 err << "unable to setup timers for periodically running the"
1328 " reclamation of the expired leases: "
1329 << ex.what() << ".";
1331 }
1332
1333 // Setup config backend polling, if configured for it.
1334 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
1335 if (ctl_info) {
1336 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
1337 // Only schedule the CB fetch timer if the fetch wait time is greater
1338 // than 0.
1339 if (fetch_time > 0) {
1340 // When we run unit tests, we want to use milliseconds unit for the
1341 // specified interval. Otherwise, we use seconds. Note that using
1342 // milliseconds as a unit in unit tests prevents us from waiting 1
1343 // second on more before the timer goes off. Instead, we wait one
1344 // millisecond which significantly reduces the test time.
1345 if (!server_->inTestMode()) {
1346 fetch_time = 1000 * fetch_time;
1347 }
1348
1349 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1351 registerTimer("Dhcp6CBFetchTimer",
1352 std::bind(&ControlledDhcpv6Srv::cbFetchUpdates,
1353 server_, CfgMgr::instance().getStagingCfg(),
1354 failure_count),
1355 fetch_time,
1357 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
1358 }
1359 }
1360
1361 // Finally, we can commit runtime option definitions in libdhcp++. This is
1362 // exception free.
1364
1366 if (notify_libraries) {
1367 return (notify_libraries);
1368 }
1369
1370 // Apply multi threading settings.
1371 // @note These settings are applied/updated only if no errors occur while
1372 // applying the new configuration.
1373 // @todo This should be fixed.
1374 try {
1375 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1376 } catch (const std::exception& ex) {
1377 err << "Error applying multi threading settings: "
1378 << ex.what();
1380 }
1381
1382 return (answer);
1383}
1384
1388 // This hook point notifies hooks libraries that the configuration of the
1389 // DHCPv6 server has completed. It provides the hook library with the pointer
1390 // to the common IO service object, new server configuration in the JSON
1391 // format and with the pointer to the configuration storage where the
1392 // parsed configuration is stored.
1393 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp6_srv_configured_)) {
1395
1396 callout_handle->setArgument("io_context", srv->getIOService());
1397 callout_handle->setArgument("network_state", srv->getNetworkState());
1398 callout_handle->setArgument("json_config", config);
1399 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1400
1401 HooksManager::callCallouts(Hooks.hooks_index_dhcp6_srv_configured_,
1402 *callout_handle);
1403
1404 // If next step is DROP, report a configuration error.
1405 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1406 string error;
1407 try {
1408 callout_handle->getArgument("error", error);
1409 } catch (NoSuchArgument const& ex) {
1410 error = "unknown error";
1411 }
1413 }
1414 }
1415
1416 return (ConstElementPtr());
1417}
1418
1422
1423 if (!srv) {
1425 "Server object not initialized, can't process config.");
1426 return (no_srv);
1427 }
1428
1430 .arg(srv->redactConfig(config)->str());
1431
1432 return (configureDhcp6Server(*srv, config, true));
1433}
1434
1435ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port /*= DHCP6_SERVER_PORT*/,
1436 uint16_t client_port /*= 0*/)
1437 : Dhcpv6Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1438 if (getInstance()) {
1440 "There is another Dhcpv6Srv instance already.");
1441 }
1442 server_ = this; // remember this instance for later use in handlers
1443
1444 // ProcessSpawn uses IO service to handle signal set events.
1446
1447 // TimerMgr uses IO service to run asynchronous timers.
1448 TimerMgr::instance()->setIOService(getIOService());
1449
1450 // Command managers use IO service to run asynchronous socket operations.
1453
1454 // Set the HTTP default socket address to the IPv6 (vs IPv4) loopback.
1456
1457 // Set the HTTP authentication default realm.
1459
1460 // Set the HTTP supported service.
1462
1463 // DatabaseConnection uses IO service to run asynchronous timers.
1465
1466 // These are the commands always supported by the DHCPv6 server.
1467 // Please keep the list in alphabetic order.
1468 CommandMgr::instance().registerCommand("build-report",
1469 std::bind(&ControlledDhcpv6Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1470
1471 CommandMgr::instance().registerCommand("config-backend-pull",
1472 std::bind(&ControlledDhcpv6Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1473
1475 std::bind(&ControlledDhcpv6Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1476
1477 CommandMgr::instance().registerCommand("config-hash-get",
1478 std::bind(&ControlledDhcpv6Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1479
1480 CommandMgr::instance().registerCommand("config-reload",
1481 std::bind(&ControlledDhcpv6Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1482
1484 std::bind(&ControlledDhcpv6Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1485
1486 CommandMgr::instance().registerCommand("config-test",
1487 std::bind(&ControlledDhcpv6Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1488
1489 CommandMgr::instance().registerCommand("config-write",
1490 std::bind(&ControlledDhcpv6Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1491
1492 CommandMgr::instance().registerCommand("dhcp-enable",
1493 std::bind(&ControlledDhcpv6Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1494
1495 CommandMgr::instance().registerCommand("dhcp-disable",
1496 std::bind(&ControlledDhcpv6Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1497
1498 CommandMgr::instance().registerCommand("interface-add",
1499 std::bind(&ControlledDhcpv6Srv::commandInterfaceAddHandler, this, ph::_1, ph::_2));
1500
1501 CommandMgr::instance().registerCommand("interface-list",
1502 std::bind(&ControlledDhcpv6Srv::commandInterfaceListHandler, this, ph::_1, ph::_2));
1503
1504 CommandMgr::instance().registerCommand("interface-redetect",
1505 std::bind(&ControlledDhcpv6Srv::commandInterfaceRedetectHandler, this, ph::_1, ph::_2));
1506
1507 CommandMgr::instance().registerCommand("kea-lfc-start",
1508 std::bind(&ControlledDhcpv6Srv::commandLfcStartHandler, this, ph::_1, ph::_2));
1509
1510 CommandMgr::instance().registerCommand("leases-reclaim",
1511 std::bind(&ControlledDhcpv6Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1512
1513 CommandMgr::instance().registerCommand("subnet6-select-test",
1514 std::bind(&ControlledDhcpv6Srv::commandSubnet6SelectTestHandler, this, ph::_1, ph::_2));
1515
1516 CommandMgr::instance().registerCommand("server-tag-get",
1517 std::bind(&ControlledDhcpv6Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1518
1520 std::bind(&ControlledDhcpv6Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1521
1523 std::bind(&ControlledDhcpv6Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1524
1525 CommandMgr::instance().registerCommand("version-get",
1526 std::bind(&ControlledDhcpv6Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1527
1528 // Register statistic related commands
1529 CommandMgr::instance().registerCommand("statistic-get",
1530 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1531
1532 CommandMgr::instance().registerCommand("statistic-reset",
1533 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1534
1535 CommandMgr::instance().registerCommand("statistic-remove",
1536 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1537
1538 CommandMgr::instance().registerCommand("statistic-get-all",
1539 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1540
1541 CommandMgr::instance().registerCommand("statistic-global-get-all",
1542 std::bind(&StatsMgr::statisticGlobalGetAllHandler, ph::_1, ph::_2));
1543
1544 CommandMgr::instance().registerCommand("statistic-reset-all",
1545 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1546
1547 CommandMgr::instance().registerCommand("statistic-remove-all",
1548 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1549
1550 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1551 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1552
1553 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1554 std::bind(&ControlledDhcpv6Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1555
1556 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1557 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1558
1559 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1561}
1562
1564 setExitValue(exit_value);
1565 getIOService()->stop(); // Stop ASIO transmissions
1566 shutdown(); // Initiate DHCPv6 shutdown procedure.
1567}
1568
1570 try {
1571 MultiThreadingMgr::instance().apply(false, 0, 0);
1574
1575 // The closure captures either a shared pointer (memory leak)
1576 // or a raw pointer (pointing to a deleted object).
1580
1581 timer_mgr_->unregisterTimers();
1582
1583 cleanup();
1584
1585 // Close command sockets.
1588
1589 // Deregister any registered commands (please keep in alphabetic order)
1590 CommandMgr::instance().deregisterCommand("build-report");
1591 CommandMgr::instance().deregisterCommand("config-backend-pull");
1593 CommandMgr::instance().deregisterCommand("config-hash-get");
1594 CommandMgr::instance().deregisterCommand("config-reload");
1596 CommandMgr::instance().deregisterCommand("config-test");
1597 CommandMgr::instance().deregisterCommand("config-write");
1598 CommandMgr::instance().deregisterCommand("dhcp-disable");
1599 CommandMgr::instance().deregisterCommand("dhcp-enable");
1600 CommandMgr::instance().deregisterCommand("interface-add");
1601 CommandMgr::instance().deregisterCommand("interface-list");
1602 CommandMgr::instance().deregisterCommand("interface-redetect");
1603 CommandMgr::instance().deregisterCommand("kea-lfc-start");
1604 CommandMgr::instance().deregisterCommand("leases-reclaim");
1605 CommandMgr::instance().deregisterCommand("subnet6-select-test");
1606 CommandMgr::instance().deregisterCommand("server-tag-get");
1608 CommandMgr::instance().deregisterCommand("statistic-get");
1609 CommandMgr::instance().deregisterCommand("statistic-get-all");
1610 CommandMgr::instance().deregisterCommand("statistic-global-get-all");
1611 CommandMgr::instance().deregisterCommand("statistic-remove");
1612 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1613 CommandMgr::instance().deregisterCommand("statistic-reset");
1614 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1615 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1616 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1617 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1618 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1620 CommandMgr::instance().deregisterCommand("version-get");
1621
1622 // Reset DatabaseConnection IO service.
1624 } catch (...) {
1625 // Don't want to throw exceptions from the destructor. The server
1626 // is shutting down anyway.
1627 }
1628
1629 server_ = NULL; // forget this instance. There should be no callback anymore
1630 // at this stage anyway.
1631}
1632
1633void
1634ControlledDhcpv6Srv::reclaimExpiredLeases(const size_t max_leases,
1635 const uint16_t timeout,
1636 const bool remove_lease,
1637 const uint16_t max_unwarned_cycles) {
1638 try {
1639 if (network_state_->isServiceEnabled()) {
1640 server_->alloc_engine_->reclaimExpiredLeases6(max_leases, timeout,
1641 remove_lease,
1642 max_unwarned_cycles);
1643 } else {
1645 .arg(CfgMgr::instance().getCurrentCfg()->
1646 getCfgExpiration()->getReclaimTimerWaitTime());
1647 }
1648 } catch (const std::exception& ex) {
1650 .arg(ex.what());
1651 }
1652 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1654}
1655
1656void
1657ControlledDhcpv6Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1658 if (network_state_->isServiceEnabled()) {
1659 server_->alloc_engine_->deleteExpiredReclaimedLeases6(secs);
1660 }
1661
1662 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1664}
1665
1666bool
1667ControlledDhcpv6Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1668 if (!db_reconnect_ctl) {
1669 // This should never happen
1671 return (false);
1672 }
1673
1674 // Disable service until the connection is recovered.
1675 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1676 db_reconnect_ctl->alterServiceState()) {
1677 network_state_->disableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1678 }
1679
1681 .arg(db_reconnect_ctl->id())
1682 .arg(db_reconnect_ctl->timerName());
1683
1684 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1685 // return false.
1686 if (!db_reconnect_ctl->retriesLeft() ||
1687 !db_reconnect_ctl->retryInterval()) {
1688 if (db_reconnect_ctl->exitOnFailure()) {
1690 .arg(db_reconnect_ctl->retriesLeft())
1691 .arg(db_reconnect_ctl->retryInterval())
1692 .arg(db_reconnect_ctl->id())
1693 .arg(db_reconnect_ctl->timerName());
1694 shutdownServer(EXIT_FAILURE);
1695 } else {
1697 .arg(db_reconnect_ctl->retriesLeft())
1698 .arg(db_reconnect_ctl->retryInterval())
1699 .arg(db_reconnect_ctl->id())
1700 .arg(db_reconnect_ctl->timerName());
1701 }
1702 return (false);
1703 }
1704
1705 return (true);
1706}
1707
1708bool
1709ControlledDhcpv6Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1710 if (!db_reconnect_ctl) {
1711 // This should never happen
1713 return (false);
1714 }
1715
1716 // Enable service after the connection is recovered.
1717 if (db_reconnect_ctl->retriesLeft() != db_reconnect_ctl->maxRetries() &&
1718 db_reconnect_ctl->alterServiceState()) {
1719 network_state_->enableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1720 }
1721
1723 .arg(db_reconnect_ctl->id())
1724 .arg(db_reconnect_ctl->timerName());
1725
1726 db_reconnect_ctl->resetRetries();
1727
1728 return (true);
1729}
1730
1731bool
1732ControlledDhcpv6Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1733 if (!db_reconnect_ctl) {
1734 // This should never happen
1736 return (false);
1737 }
1738
1739 if (db_reconnect_ctl->exitOnFailure()) {
1741 .arg(db_reconnect_ctl->maxRetries())
1742 .arg(db_reconnect_ctl->id())
1743 .arg(db_reconnect_ctl->timerName());
1744 shutdownServer(EXIT_FAILURE);
1745 } else {
1747 .arg(db_reconnect_ctl->maxRetries())
1748 .arg(db_reconnect_ctl->id())
1749 .arg(db_reconnect_ctl->timerName());
1750 }
1751
1752 return (true);
1753}
1754
1755void
1756ControlledDhcpv6Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1757 if (!reconnect_ctl) {
1758 // This should never happen
1760 return;
1761 }
1762
1763 if (reconnect_ctl->exitOnFailure()) {
1765 .arg(reconnect_ctl->maxRetries());
1766 shutdownServer(EXIT_FAILURE);
1767 } else {
1769 .arg(reconnect_ctl->maxRetries());
1770 }
1771}
1772
1773void
1774ControlledDhcpv6Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1775 boost::shared_ptr<unsigned> failure_count) {
1776 // stop thread pool (if running)
1777 MultiThreadingCriticalSection cs;
1778
1779 try {
1780 // Fetch any configuration backend updates since our last fetch.
1781 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1782 CBControlDHCPv6::FetchMode::FETCH_UPDATE);
1783 (*failure_count) = 0;
1784
1785 } catch (const std::exception& ex) {
1787 .arg(ex.what());
1788
1789 // We allow at most 10 consecutive failures after which we stop
1790 // making further attempts to fetch the configuration updates.
1791 // Let's return without re-scheduling the timer.
1792 if (++(*failure_count) > 10) {
1795 return;
1796 }
1797 }
1798
1799 // Reschedule the timer to fetch new updates or re-try if
1800 // the previous attempt resulted in an error.
1801 if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
1802 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
1803 }
1804}
1805
1806} // namespace dhcp
1807} // namespace isc
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 an unrecoverable error occurs.
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.
static CommandMgr & instance()
CommandMgr is a singleton class.
static std::string DEFAULT_AUTHENTICATION_REALM
Default HTTP authentication realm.
static isc::asiolink::IOAddress DEFAULT_SOCKET_ADDRESS
Default socket address (127.0.0.1).
static std::string SUPPORTED_SERVICE
Supported service.
void closeCommandSockets()
Close http control sockets.
static HttpCommandMgr & instance()
HttpCommandMgr is a singleton class.
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the http command manager.
static UnixCommandMgr & instance()
UnixCommandMgr is a singleton class.
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the unix command manager.
void closeCommandSockets()
Shuts down any open unix control sockets.
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:299
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:354
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:349
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.
Represents selection of interfaces for DHCP server.
Definition cfg_iface.h:131
static OpenSocketsFailedCallback open_sockets_failed_callback_
Optional callback function to invoke if all retries of the opening sockets fail.
Definition cfg_iface.h:369
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition cfgmgr.cc:121
void commit()
Commits the staging configuration.
Definition cfgmgr.cc:93
void clearStagingConfiguration()
Remove staging configuration.
Definition cfgmgr.cc:88
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
static void apply(data::ConstElementPtr value)
apply multi threading configuration
void insert(const ClientClass &class_name)
Insert an element.
Definition classify.h:161
Controlled version of the DHCPv6 server.
bool getShutdown() const
Return the server shutdown flag value.
isc::data::ConstElementPtr commandVersionGetHandler(const std::string &command, isc::data::ConstElementPtr args)
@Brief handler for processing 'version-get' command
void init(const std::string &config_file)
Initializes the server.
void cleanup()
Performs cleanup, immediately before termination.
isc::data::ConstElementPtr commandConfigSetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'config-set' command
isc::data::ConstElementPtr commandInterfaceAddHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'interface-add' command.
isc::data::ConstElementPtr commandInterfaceRedetectHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'interface-redetect' command.
isc::data::ConstElementPtr commandShutdownHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'shutdown' command.
isc::data::ConstElementPtr commandConfigBackendPullHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for config-backend-pull command
isc::data::ConstElementPtr commandLfcStartHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'kea-lfc-start' command
isc::data::ConstElementPtr commandConfigHashGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'config-hash-get' command
isc::data::ConstElementPtr commandServerTagGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for server-tag-get command
isc::data::ConstElementPtr commandStatisticSetMaxSampleCountAllHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'statistic-sample-count-set-all' command
isc::data::ConstElementPtr commandStatisticSetMaxSampleAgeAllHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'statistic-sample-age-set-all' command
isc::data::ConstElementPtr commandStatusGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'status-get' command
isc::data::ConstElementPtr commandDhcpEnableHandler(const std::string &command, isc::data::ConstElementPtr args)
A handler for processing 'dhcp-enable' command.
isc::data::ConstElementPtr commandConfigReloadHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'config-reload' command.
isc::data::ConstElementPtr commandLeasesReclaimHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'leases-reclaim' command.
isc::data::ConstElementPtr commandConfigWriteHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'config-write' command
isc::data::ConstElementPtr commandBuildReportHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'build-report' command
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.
isc::data::ConstElementPtr commandConfigGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'config-get' command
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.
isc::data::ConstElementPtr commandInterfaceListHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'interface-list' command.
isc::data::ConstElementPtr commandSubnet6SelectTestHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'subnet6-select-test' command.
ControlledDhcpv6Srv(uint16_t server_port=DHCP6_SERVER_PORT, uint16_t client_port=0)
Constructor.
isc::data::ConstElementPtr commandDhcpDisableHandler(const std::string &command, isc::data::ConstElementPtr args)
A handler for processing 'dhcp-disable' command.
isc::data::ConstElementPtr commandConfigTestHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'config-test' command
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:373
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
Definition dhcp6_srv.h:1264
uint16_t getServerPort() const
Get UDP port on which server should listen.
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:1272
Dhcpv6Srv(uint16_t server_port=DHCP6_SERVER_PORT, uint16_t client_port=0)
Default constructor.
Definition dhcp6_srv.cc:274
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
volatile bool shutdown_
Indicates if shutdown is in progress.
Definition dhcp6_srv.h:1248
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
size_t size() const
Return the number of interfaces.
Definition iface_mgr.h:635
const IfaceCollection & getIfaces()
Returns container with all interfaces.
Definition iface_mgr.h:942
void detectIfaces(bool update_only=false)
Detects network interfaces.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:52
Parser for the configuration of interfaces.
void parseInterfacesList(const CfgIfacePtr &cfg_iface, isc::data::ConstElementPtr ifaces_list)
parses interfaces-list structure
static TrackingLeaseMgr & instance()
Return current lease manager.
static bool init_allocators_
Flag which indicates if allocators must be initialized.
static void destroy()
Destroy lease manager.
static bool haveInstance()
Indicates if the lease manager has been instantiated.
virtual data::ElementPtr getStatus() const
Return status information.
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition libdhcp++.cc:248
Concrete implementation of a lease database backend using flat file.
static bool isLFCProcessRunning(const std::string file_name, Universe u)
Check if LFC is running.
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).
RAII class creating a critical section for the receiver thread.
Definition iface_mgr.h:1867
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:108
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:270
isc::asiolink::IOSignalSetPtr signal_set_
A pointer to the object installing custom signal handlers.
Definition daemon.h:286
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition daemon.h:292
void checkWriteConfigFile(std::string &file)
Checks the to-be-written configuration file name.
Definition daemon.cc:133
void setExitValue(int value)
Sets the exit value.
Definition daemon.h:242
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition daemon.cc:298
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 ...
Dhcp4Hooks Hooks
Definition dhcp4_srv.cc:213
@ D6O_INTERFACE_ID
Definition dhcp6.h:38
@ 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.
static isc::data::ConstElementPtr statisticGlobalGetAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-global-get-all 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_COMMAND_UNSUPPORTED
Status code indicating that the specified command is not supported.
const int CONTROL_RESULT_FATAL_ERROR
Status code indicating that the command was unsuccessful and the configuration could not be reverted ...
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
@ error
Definition db_log.h:124
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
boost::shared_ptr< const Subnet6 > ConstSubnet6Ptr
A const pointer to a Subnet6 object.
Definition subnet.h:620
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.
const isc::log::MessageID DHCP6_RECLAIM_EXPIRED_LEASES_SKIPPED
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:555
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
boost::shared_ptr< CfgIface > CfgIfacePtr
A pointer to the CfgIface .
Definition cfg_iface.h:522
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
boost::shared_ptr< SharedNetwork6 > SharedNetwork6Ptr
Pointer to SharedNetwork6 object.
const isc::log::MessageID DHCP6_FATAL_OPEN_SOCKETS_FAILED
const isc::log::MessageID DHCP6_FATAL_DB_RECONNECT_DISABLED
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_FATAL_DB_RECONNECT_FAILED
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
const int DBG_DHCP6_BASIC
Debug level used to trace basic operations within the code.
Definition dhcp6_log.h:31
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
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
const isc::log::MessageID DHCP6_FATAL_DYNAMIC_RECONFIGURATION_FAIL
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
void decodeFormattedHexString(const string &hex_string, vector< uint8_t > &binary)
Converts a formatted string of hexadecimal digits into a vector.
Definition str.cc:212
vector< uint8_t > quotedStringToBinary(const string &quoted_string)
Converts a string in quotes into vector.
Definition str.cc:139
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.
Subnet selector used to specify parameters used to select a subnet.
std::string iface_name_
Name of the interface on which the message was received.
ClientClasses client_classes_
Classes that the client belongs to.
asiolink::IOAddress remote_address_
Source address of the message.
OptionPtr interface_id_
Interface id option.
asiolink::IOAddress first_relay_linkaddr_
First relay link address.