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