Kea 2.2.0
ctrl_dhcp6_srv.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2022 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
10#include <cc/data.h>
12#include <config/command_mgr.h>
13#include <dhcp/libdhcp++.h>
15#include <dhcp6/dhcp6_log.h>
16#include <dhcp6/dhcp6to4_ipc.h>
21#include <dhcpsrv/cfgmgr.h>
22#include <dhcpsrv/db_type.h>
24#include <dhcpsrv/host_mgr.h>
25#include <hooks/hooks.h>
26#include <hooks/hooks_manager.h>
27#include <stats/stats_mgr.h>
29
30#include <signal.h>
31
32#include <sstream>
33
34using namespace isc::asiolink;
35using namespace isc::config;
36using namespace isc::data;
37using namespace isc::db;
38using namespace isc::dhcp;
39using namespace isc::hooks;
40using namespace isc::stats;
41using namespace isc::util;
42using namespace std;
43namespace ph = std::placeholders;
44
45namespace {
46
48struct CtrlDhcp6Hooks {
49 int hooks_index_dhcp6_srv_configured_;
50
52 CtrlDhcp6Hooks() {
53 hooks_index_dhcp6_srv_configured_ = HooksManager::registerHook("dhcp6_srv_configured");
54 }
55
56};
57
58// Declare a Hooks object. As this is outside any function or method, it
59// will be instantiated (and the constructor run) when the module is loaded.
60// As a result, the hook indexes will be defined before any method in this
61// module is called.
62CtrlDhcp6Hooks Hooks;
63
64// Name of the file holding server identifier.
65static const char* SERVER_DUID_FILE = "kea-dhcp6-serverid";
66
76void signalHandler(int signo) {
77 // SIGHUP signals a request to reconfigure the server.
78 if (signo == SIGHUP) {
79 ControlledDhcpv6Srv::processCommand("config-reload",
81 } else if ((signo == SIGTERM) || (signo == SIGINT)) {
82 ControlledDhcpv6Srv::processCommand("shutdown",
84 }
85}
86
87}
88
89namespace isc {
90namespace dhcp {
91
92ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL;
93
95ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
96 // This is a configuration backend implementation that reads the
97 // configuration from a JSON file.
98
101
102 // Basic sanity check: file name must not be empty.
103 try {
104 if (file_name.empty()) {
105 // Basic sanity check: file name must not be empty.
106 isc_throw(isc::BadValue, "JSON configuration file not specified. Please "
107 "use -c command line option.");
108 }
109
110 // Read contents of the file and parse it as JSON
111 Parser6Context parser;
112 json = parser.parseFile(file_name, Parser6Context::PARSER_DHCP6);
113 if (!json) {
114 isc_throw(isc::BadValue, "no configuration found");
115 }
116
117 // Let's do sanity check before we call json->get() which
118 // works only for map.
119 if (json->getType() != isc::data::Element::map) {
120 isc_throw(isc::BadValue, "Configuration file is expected to be "
121 "a map, i.e., start with { and end with } and contain "
122 "at least an entry called 'Dhcp6' that itself is a map. "
123 << file_name
124 << " is a valid JSON, but its top element is not a map."
125 " Did you forget to add { } around your configuration?");
126 }
127
128 // Use parsed JSON structures to configure the server
129 result = ControlledDhcpv6Srv::processCommand("config-set", json);
130 if (!result) {
131 // Undetermined status of the configuration. This should never
132 // happen, but as the configureDhcp6Server returns a pointer, it is
133 // theoretically possible that it will return NULL.
134 isc_throw(isc::BadValue, "undefined result of "
135 "processCommand(\"config-set\", json)");
136 }
137
138 // Now check is the returned result is successful (rcode=0) or not
139 // (see @ref isc::config::parseAnswer).
140 int rcode;
141 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
142 if (rcode != CONTROL_RESULT_SUCCESS) {
143 string reason = comment ? comment->stringValue() :
144 "no details available";
145 isc_throw(isc::BadValue, reason);
146 }
147 } catch (const std::exception& ex) {
148 // If configuration failed at any stage, we drop the staging
149 // configuration and continue to use the previous one.
151
153 .arg(file_name).arg(ex.what());
154 isc_throw(isc::BadValue, "configuration error using file '"
155 << file_name << "': " << ex.what());
156 }
157
159 .arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
160 .arg(MultiThreadingMgr::instance().getThreadPoolSize())
161 .arg(MultiThreadingMgr::instance().getPacketQueueSize());
162
163 return (result);
164}
165
166void
167ControlledDhcpv6Srv::init(const std::string& file_name) {
168 // Keep the call timestamp.
169 start_ = boost::posix_time::second_clock::universal_time();
170
171 // Configure the server using JSON file.
172 ConstElementPtr result = loadConfigFile(file_name);
173
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
182 // We don't need to call openActiveSockets() or startD2() as these
183 // methods are called in processConfig() which is called by
184 // processCommand("config-set", ...)
185
186 // Set signal handlers. When the SIGHUP is received by the process
187 // the server reconfiguration will be triggered. When SIGTERM or
188 // SIGINT will be received, the server will start shutting down.
189 signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
190
191 signal_set_->add(SIGINT);
192 signal_set_->add(SIGHUP);
193 signal_set_->add(SIGTERM);
194}
195
197 // Nothing to do here. No need to disconnect from anything.
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
226 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
227}
228
230ControlledDhcpv6Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
231 // stop thread pool (if running)
233
234 // Clear the packet queue.
235 MultiThreadingMgr::instance().getThreadPool().reset();
236
237 try {
239 HookLibsCollection loaded = HooksManager::getLibraryInfo();
240 HooksManager::prepareUnloadLibraries();
241 static_cast<void>(HooksManager::unloadLibraries());
242 bool status = HooksManager::loadLibraries(loaded);
243 if (!status) {
244 isc_throw(Unexpected, "Failed to reload hooks libraries.");
245 }
246 } catch (const std::exception& ex) {
248 ConstElementPtr answer = isc::config::createAnswer(1, ex.what());
249 return (answer);
250 }
252 "Hooks libraries successfully reloaded.");
253 return (answer);
254}
255
257ControlledDhcpv6Srv::commandConfigReloadHandler(const string&,
258 ConstElementPtr /*args*/) {
259 // Get configuration file name.
260 std::string file = ControlledDhcpv6Srv::getInstance()->getConfigFile();
261 try {
263 auto result = loadConfigFile(file);
265 return (result);
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
278ControlledDhcpv6Srv::commandConfigGetHandler(const string&,
279 ConstElementPtr /*args*/) {
280 ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
281
282 return (createAnswer(0, config));
283}
284
286ControlledDhcpv6Srv::commandConfigWriteHandler(const string&,
287 ConstElementPtr args) {
288 string filename;
289
290 if (args) {
291 if (args->getType() != Element::map) {
292 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
293 }
294 ConstElementPtr filename_param = args->get("filename");
295 if (filename_param) {
296 if (filename_param->getType() != Element::string) {
298 "passed parameter 'filename' is not a string"));
299 }
300 filename = filename_param->stringValue();
301 }
302 }
303
304 if (filename.empty()) {
305 // filename parameter was not specified, so let's use whatever we remember
306 // from the command-line
307 filename = getConfigFile();
308 }
309
310 if (filename.empty()) {
311 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
312 "Please specify filename explicitly."));
313 }
314
315 // Ok, it's time to write the file.
316 size_t size = 0;
317 try {
318 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
319 size = writeConfigFile(filename, cfg);
320 } catch (const isc::Exception& ex) {
321 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during write-config:")
322 + ex.what()));
323 }
324 if (size == 0) {
325 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
326 + filename));
327 }
328
329 // Ok, it's time to return the successful response.
331 params->set("size", Element::create(static_cast<long long>(size)));
332 params->set("filename", Element::create(filename));
333
334 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
335 + filename + " successful", params));
336}
337
339ControlledDhcpv6Srv::commandConfigSetHandler(const string&,
340 ConstElementPtr args) {
341 const int status_code = CONTROL_RESULT_ERROR;
342 ConstElementPtr dhcp6;
343 string message;
344
345 // Command arguments are expected to be:
346 // { "Dhcp6": { ... } }
347 if (!args) {
348 message = "Missing mandatory 'arguments' parameter.";
349 } else {
350 dhcp6 = args->get("Dhcp6");
351 if (!dhcp6) {
352 message = "Missing mandatory 'Dhcp6' parameter.";
353 } else if (dhcp6->getType() != Element::map) {
354 message = "'Dhcp6' parameter expected to be a map.";
355 }
356 }
357
358 // Check unsupported objects.
359 if (message.empty()) {
360 for (auto obj : args->mapValue()) {
361 const string& obj_name = obj.first;
362 if (obj_name != "Dhcp6") {
364 .arg(obj_name);
365 if (message.empty()) {
366 message = "Unsupported '" + obj_name + "' parameter";
367 } else {
368 message += " (and '" + obj_name + "')";
369 }
370 }
371 }
372 if (!message.empty()) {
373 message += ".";
374 }
375 }
376
377 if (!message.empty()) {
378 // Something is amiss with arguments, return a failure response.
379 ConstElementPtr result = isc::config::createAnswer(status_code,
380 message);
381 return (result);
382 }
383
384 // stop thread pool (if running)
386
387 // disable multi-threading (it will be applied by new configuration)
388 // this must be done in order to properly handle MT to ST transition
389 // when 'multi-threading' structure is missing from new config
390 MultiThreadingMgr::instance().apply(false, 0, 0);
391
392 // We are starting the configuration process so we should remove any
393 // staging configuration that has been created during previous
394 // configuration attempts.
396
397 // Parse the logger configuration explicitly into the staging config.
398 // Note this does not alter the current loggers, they remain in
399 // effect until we apply the logging config below. If no logging
400 // is supplied logging will revert to default logging.
401 Daemon::configureLogger(dhcp6, CfgMgr::instance().getStagingCfg());
402
403 // Let's apply the new logging. We do it early, so we'll be able to print
404 // out what exactly is wrong with the new config in case of problems.
405 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
406
407 // Now we configure the server proper.
408 ConstElementPtr result = processConfig(dhcp6);
409
410 // If the configuration parsed successfully, apply the new logger
411 // configuration and the commit the new configuration. We apply
412 // the logging first in case there's a configuration failure.
413 int rcode = 0;
414 isc::config::parseAnswer(rcode, result);
415 if (rcode == CONTROL_RESULT_SUCCESS) {
416 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
417
418 // Use new configuration.
420 } else {
421 // Ok, we applied the logging from the upcoming configuration, but
422 // there were problems with the config. As such, we need to back off
423 // and revert to the previous logging configuration.
424 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
425
426 if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
427 // Not initial configuration so someone can believe we reverted
428 // to the previous configuration. It is not the case so be clear
429 // about this.
431 }
432 }
433
434 return (result);
435}
436
438ControlledDhcpv6Srv::commandConfigTestHandler(const string&,
439 ConstElementPtr args) {
440 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
441 ConstElementPtr dhcp6;
442 string message;
443
444 // Command arguments are expected to be:
445 // { "Dhcp6": { ... } }
446 if (!args) {
447 message = "Missing mandatory 'arguments' parameter.";
448 } else {
449 dhcp6 = args->get("Dhcp6");
450 if (!dhcp6) {
451 message = "Missing mandatory 'Dhcp6' parameter.";
452 } else if (dhcp6->getType() != Element::map) {
453 message = "'Dhcp6' parameter expected to be a map.";
454 }
455 }
456
457 // Check unsupported objects.
458 if (message.empty()) {
459 for (auto obj : args->mapValue()) {
460 const string& obj_name = obj.first;
461 if (obj_name != "Dhcp6") {
463 .arg(obj_name);
464 if (message.empty()) {
465 message = "Unsupported '" + obj_name + "' parameter";
466 } else {
467 message += " (and '" + obj_name + "')";
468 }
469 }
470 }
471 if (!message.empty()) {
472 message += ".";
473 }
474 }
475
476 if (!message.empty()) {
477 // Something is amiss with arguments, return a failure response.
478 ConstElementPtr result = isc::config::createAnswer(status_code,
479 message);
480 return (result);
481 }
482
483 // stop thread pool (if running)
485
486 // We are starting the configuration process so we should remove any
487 // staging configuration that has been created during previous
488 // configuration attempts.
490
491 // Now we check the server proper.
492 return (checkConfig(dhcp6));
493}
494
496ControlledDhcpv6Srv::commandDhcpDisableHandler(const std::string&,
497 ConstElementPtr args) {
498 std::ostringstream message;
499 int64_t max_period = 0;
500 std::string origin;
501
502 // If the args map does not contain 'origin' parameter, the default type
503 // will be used (user command).
505
506 // Parse arguments to see if the 'max-period' or 'origin' parameters have
507 // been specified.
508 if (args) {
509 // Arguments must be a map.
510 if (args->getType() != Element::map) {
511 message << "arguments for the 'dhcp-disable' command must be a map";
512
513 } else {
514 ConstElementPtr max_period_element = args->get("max-period");
515 // max-period is optional.
516 if (max_period_element) {
517 // It must be an integer, if specified.
518 if (max_period_element->getType() != Element::integer) {
519 message << "'max-period' argument must be a number";
520
521 } else {
522 // It must be positive integer.
523 max_period = max_period_element->intValue();
524 if (max_period <= 0) {
525 message << "'max-period' must be positive integer";
526 }
527 }
528 }
529 ConstElementPtr origin_element = args->get("origin");
530 // The 'origin' parameter is optional.
531 if (origin_element) {
532 // It must be a string, if specified.
533 if (origin_element->getType() != Element::string) {
534 message << "'origin' argument must be a string";
535
536 } else {
537 origin = origin_element->stringValue();
538 if (origin == "ha-partner") {
540 } else if (origin != "user") {
541 if (origin.empty()) {
542 origin = "(empty string)";
543 }
544 message << "invalid value used for 'origin' parameter: "
545 << origin;
546 }
547 }
548 }
549 }
550 }
551
552 // No error occurred, so let's disable the service.
553 if (message.tellp() == 0) {
554 message << "DHCPv6 service disabled";
555 if (max_period > 0) {
556 message << " for " << max_period << " seconds";
557
558 // The user specified that the DHCP service should resume not
559 // later than in max-period seconds. If the 'dhcp-enable' command
560 // is not sent, the DHCP service will resume automatically.
561 network_state_->delayedEnableAll(static_cast<unsigned>(max_period),
562 type);
563 }
564 network_state_->disableService(type);
565
566 // Success.
567 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
568 }
569
570 // Failure.
571 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
572}
573
575ControlledDhcpv6Srv::commandDhcpEnableHandler(const std::string&,
576 ConstElementPtr args) {
577 std::ostringstream message;
578 std::string origin;
579
580 // If the args map does not contain 'origin' parameter, the default type
581 // will be used (user command).
583
584 // Parse arguments to see if the 'origin' parameter has been specified.
585 if (args) {
586 // Arguments must be a map.
587 if (args->getType() != Element::map) {
588 message << "arguments for the 'dhcp-enable' command must be a map";
589
590 } else {
591 ConstElementPtr origin_element = args->get("origin");
592 // The 'origin' parameter is optional.
593 if (origin_element) {
594 // It must be a string, if specified.
595 if (origin_element->getType() != Element::string) {
596 message << "'origin' argument must be a string";
597
598 } else {
599 origin = origin_element->stringValue();
600 if (origin == "ha-partner") {
602 } else if (origin != "user") {
603 if (origin.empty()) {
604 origin = "(empty string)";
605 }
606 message << "invalid value used for 'origin' parameter: "
607 << origin;
608 }
609 }
610 }
611 }
612 }
613
614 // No error occurred, so let's enable the service.
615 if (message.tellp() == 0) {
616 network_state_->enableService(type);
617
618 // Success.
620 "DHCP service successfully enabled"));
621 }
622
623 // Failure.
624 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
625}
626
628ControlledDhcpv6Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
630 ElementPtr arguments = Element::createMap();
631 arguments->set("extended", extended);
634 arguments);
635 return (answer);
636}
637
639ControlledDhcpv6Srv::commandBuildReportHandler(const string&,
641 ConstElementPtr answer =
643 return (answer);
644}
645
647ControlledDhcpv6Srv::commandLeasesReclaimHandler(const string&,
648 ConstElementPtr args) {
649 int status_code = CONTROL_RESULT_ERROR;
650 string message;
651
652 // args must be { "remove": <bool> }
653 if (!args) {
654 message = "Missing mandatory 'remove' parameter.";
655 } else {
656 ConstElementPtr remove_name = args->get("remove");
657 if (!remove_name) {
658 message = "Missing mandatory 'remove' parameter.";
659 } else if (remove_name->getType() != Element::boolean) {
660 message = "'remove' parameter expected to be a boolean.";
661 } else {
662 bool remove_lease = remove_name->boolValue();
663 server_->alloc_engine_->reclaimExpiredLeases6(0, 0, remove_lease);
664 status_code = 0;
665 message = "Reclamation of expired leases is complete.";
666 }
667 }
668 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
669 return (answer);
670}
671
673ControlledDhcpv6Srv::commandServerTagGetHandler(const std::string&,
675 const std::string& tag =
676 CfgMgr::instance().getCurrentCfg()->getServerTag();
677 ElementPtr response = Element::createMap();
678 response->set("server-tag", Element::create(tag));
679
680 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
681}
682
684ControlledDhcpv6Srv::commandConfigBackendPullHandler(const std::string&,
686 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
687 if (!ctl_info) {
688 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
689 }
690
691 // stop thread pool (if running)
693
694 // Reschedule the periodic CB fetch.
695 if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
696 TimerMgr::instance()->cancel("Dhcp6CBFetchTimer");
697 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
698 }
699
700 // Code from cbFetchUpdates.
701 // The configuration to use is the current one because this is called
702 // after the configuration manager commit.
703 try {
704 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
705 auto mode = CBControlDHCPv6::FetchMode::FETCH_UPDATE;
706 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
707 } catch (const std::exception& ex) {
709 .arg(ex.what());
711 "On demand configuration update failed: " +
712 string(ex.what())));
713 }
715 "On demand configuration update successful."));
716}
717
719ControlledDhcpv6Srv::commandStatusGetHandler(const string&,
720 ConstElementPtr /*args*/) {
722 status->set("pid", Element::create(static_cast<int>(getpid())));
723
724 auto now = boost::posix_time::second_clock::universal_time();
725 // Sanity check: start_ is always initialized.
726 if (!start_.is_not_a_date_time()) {
727 auto uptime = now - start_;
728 status->set("uptime", Element::create(uptime.total_seconds()));
729 }
730
731 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
732 if (!last_commit.is_not_a_date_time()) {
733 auto reload = now - last_commit;
734 status->set("reload", Element::create(reload.total_seconds()));
735 }
736
737 auto& mt_mgr = MultiThreadingMgr::instance();
738 if (mt_mgr.getMode()) {
739 status->set("multi-threading-enabled", Element::create(true));
740 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
741 MultiThreadingMgr::instance().getThreadPoolSize())));
742 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
743 MultiThreadingMgr::instance().getPacketQueueSize())));
744 ElementPtr queue_stats = Element::createList();
745 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
746 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
747 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
748 status->set("packet-queue-statistics", queue_stats);
749
750 } else {
751 status->set("multi-threading-enabled", Element::create(false));
752 }
753
754 // Iterate through the interfaces and get all the errors.
755 ElementPtr socket_errors(Element::createList());
756 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
757 for (std::string const& error : interface->getErrors()) {
758 socket_errors->add(Element::create(error));
759 }
760 }
761
762 // Abstract the information from all sockets into a single status.
764 if (socket_errors->empty()) {
765 sockets->set("status", Element::create("ready"));
766 } else {
767 ReconnectCtlPtr const reconnect_ctl(
768 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
769 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
770 sockets->set("status", Element::create("retrying"));
771 } else {
772 sockets->set("status", Element::create("failed"));
773 }
774 sockets->set("errors", socket_errors);
775 }
776 status->set("sockets", sockets);
777
778 return (createAnswer(0, status));
779}
780
782ControlledDhcpv6Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
783 ConstElementPtr args) {
784 StatsMgr& stats_mgr = StatsMgr::instance();
786 // Update the default parameter.
787 long max_samples = stats_mgr.getMaxSampleCountDefault();
788 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
789 "statistic-default-sample-count", Element::create(max_samples));
790 return (answer);
791}
792
794ControlledDhcpv6Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
795 ConstElementPtr args) {
796 StatsMgr& stats_mgr = StatsMgr::instance();
798 // Update the default parameter.
799 auto duration = stats_mgr.getMaxSampleAgeDefault();
800 long max_age = toSeconds(duration);
801 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
802 "statistic-default-sample-age", Element::create(max_age));
803 return (answer);
804}
805
808 ConstElementPtr args) {
809 string txt = args ? args->str() : "(none)";
810
812 .arg(command).arg(txt);
813
815
816 if (!srv) {
818 "Server object not initialized, so can't process command '" +
819 command + "', arguments: '" + txt + "'.");
820 return (no_srv);
821 }
822
823 try {
824 if (command == "shutdown") {
825 return (srv->commandShutdownHandler(command, args));
826
827 } else if (command == "libreload") {
828 return (srv->commandLibReloadHandler(command, args));
829
830 } else if (command == "config-reload") {
831 return (srv->commandConfigReloadHandler(command, args));
832
833 } else if (command == "config-set") {
834 return (srv->commandConfigSetHandler(command, args));
835
836 } else if (command == "config-get") {
837 return (srv->commandConfigGetHandler(command, args));
838
839 } else if (command == "config-test") {
840 return (srv->commandConfigTestHandler(command, args));
841
842 } else if (command == "dhcp-disable") {
843 return (srv->commandDhcpDisableHandler(command, args));
844
845 } else if (command == "dhcp-enable") {
846 return (srv->commandDhcpEnableHandler(command, args));
847
848 } else if (command == "version-get") {
849 return (srv->commandVersionGetHandler(command, args));
850
851 } else if (command == "build-report") {
852 return (srv->commandBuildReportHandler(command, args));
853
854 } else if (command == "leases-reclaim") {
855 return (srv->commandLeasesReclaimHandler(command, args));
856
857 } else if (command == "config-write") {
858 return (srv->commandConfigWriteHandler(command, args));
859
860 } else if (command == "server-tag-get") {
861 return (srv->commandServerTagGetHandler(command, args));
862
863 } else if (command == "config-backend-pull") {
864 return (srv->commandConfigBackendPullHandler(command, args));
865
866 } else if (command == "status-get") {
867 return (srv->commandStatusGetHandler(command, args));
868 }
869
870 return (isc::config::createAnswer(1, "Unrecognized command:"
871 + command));
872
873 } catch (const isc::Exception& ex) {
874 return (isc::config::createAnswer(1, "Error while processing command '"
875 + command + "':" + ex.what() +
876 ", params: '" + txt + "'"));
877 }
878}
879
882
884
885 // Single stream instance used in all error clauses
886 std::ostringstream err;
887
888 if (!srv) {
889 err << "Server object not initialized, can't process config.";
890 return (isc::config::createAnswer(1, err.str()));
891 }
892
894 .arg(srv->redactConfig(config)->str());
895
896 ConstElementPtr answer = configureDhcp6Server(*srv, config);
897
898 // Check that configuration was successful. If not, do not reopen sockets
899 // and don't bother with DDNS stuff.
900 try {
901 int rcode = 0;
902 isc::config::parseAnswer(rcode, answer);
903 if (rcode != 0) {
904 return (answer);
905 }
906 } catch (const std::exception& ex) {
907 err << "Failed to process configuration:" << ex.what();
908 return (isc::config::createAnswer(1, err.str()));
909 }
910
911 // Re-open lease and host database with new parameters.
912 try {
914 std::bind(&ControlledDhcpv6Srv::dbLostCallback, srv, ph::_1);
915
917 std::bind(&ControlledDhcpv6Srv::dbRecoveredCallback, srv, ph::_1);
918
920 std::bind(&ControlledDhcpv6Srv::dbFailedCallback, srv, ph::_1);
921
922 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
923 cfg_db->setAppendedParameters("universe=6");
924 cfg_db->createManagers();
925 // Reset counters related to connections as all managers have been recreated.
927 } catch (const std::exception& ex) {
928 err << "Unable to open database: " << ex.what();
929 return (isc::config::createAnswer(1, err.str()));
930 }
931
932 // Regenerate server identifier if needed.
933 try {
934 const std::string duid_file =
935 std::string(CfgMgr::instance().getDataDir()) + "/" +
936 std::string(SERVER_DUID_FILE);
937 DuidPtr duid = CfgMgr::instance().getStagingCfg()->getCfgDUID()->create(duid_file);
938 server_->serverid_.reset(new Option(Option::V6, D6O_SERVERID, duid->getDuid()));
939 if (duid) {
941 .arg(duid->toText())
942 .arg(duid_file);
943 }
944
945 } catch (const std::exception& ex) {
946 err << "unable to configure server identifier: " << ex.what();
947 return (isc::config::createAnswer(1, err.str()));
948 }
949
950 // Server will start DDNS communications if its enabled.
951 try {
952 srv->startD2();
953 } catch (const std::exception& ex) {
954 err << "Error starting DHCP_DDNS client after server reconfiguration: "
955 << ex.what();
956 return (isc::config::createAnswer(1, err.str()));
957 }
958
959 // Setup DHCPv4-over-DHCPv6 IPC
960 try {
962 } catch (const std::exception& ex) {
963 err << "error starting DHCPv4-over-DHCPv6 IPC "
964 " after server reconfiguration: " << ex.what();
965 return (isc::config::createAnswer(1, err.str()));
966 }
967
968 // Configure DHCP packet queueing
969 try {
971 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
972 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, qc)) {
974 .arg(IfaceMgr::instance().getPacketQueue6()->getInfoStr());
975 }
976
977 } catch (const std::exception& ex) {
978 err << "Error setting packet queue controls after server reconfiguration: "
979 << ex.what();
980 return (isc::config::createAnswer(1, err.str()));
981 }
982
983 // Configure a callback to shut down the server when the bind socket
984 // attempts exceeded.
986 std::bind(&ControlledDhcpv6Srv::openSocketsFailedCallback, srv, ph::_1);
987
988 // Configuration may change active interfaces. Therefore, we have to reopen
989 // sockets according to new configuration. It is possible that this
990 // operation will fail for some interfaces but the openSockets function
991 // guards against exceptions and invokes a callback function to
992 // log warnings. Since we allow that this fails for some interfaces there
993 // is no need to rollback configuration if socket fails to open on any
994 // of the interfaces.
995 CfgMgr::instance().getStagingCfg()->getCfgIface()->
996 openSockets(AF_INET6, srv->getServerPort());
997
998 // Install the timers for handling leases reclamation.
999 try {
1000 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
1001 setupTimers(&ControlledDhcpv6Srv::reclaimExpiredLeases,
1002 &ControlledDhcpv6Srv::deleteExpiredReclaimedLeases,
1003 server_);
1004
1005 } catch (const std::exception& ex) {
1006 err << "unable to setup timers for periodically running the"
1007 " reclamation of the expired leases: "
1008 << ex.what() << ".";
1009 return (isc::config::createAnswer(1, err.str()));
1010 }
1011
1012 // Setup config backend polling, if configured for it.
1013 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
1014 if (ctl_info) {
1015 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
1016 // Only schedule the CB fetch timer if the fetch wait time is greater
1017 // than 0.
1018 if (fetch_time > 0) {
1019 // When we run unit tests, we want to use milliseconds unit for the
1020 // specified interval. Otherwise, we use seconds. Note that using
1021 // milliseconds as a unit in unit tests prevents us from waiting 1
1022 // second on more before the timer goes off. Instead, we wait one
1023 // millisecond which significantly reduces the test time.
1024 if (!server_->inTestMode()) {
1025 fetch_time = 1000 * fetch_time;
1026 }
1027
1028 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1030 registerTimer("Dhcp6CBFetchTimer",
1031 std::bind(&ControlledDhcpv6Srv::cbFetchUpdates,
1032 server_, CfgMgr::instance().getStagingCfg(),
1033 failure_count),
1034 fetch_time,
1036 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
1037 }
1038 }
1039
1040 // Finally, we can commit runtime option definitions in libdhcp++. This is
1041 // exception free.
1043
1044 // This hook point notifies hooks libraries that the configuration of the
1045 // DHCPv6 server has completed. It provides the hook library with the pointer
1046 // to the common IO service object, new server configuration in the JSON
1047 // format and with the pointer to the configuration storage where the
1048 // parsed configuration is stored.
1049 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp6_srv_configured_)) {
1050 CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
1051
1052 callout_handle->setArgument("io_context", srv->getIOService());
1053 callout_handle->setArgument("network_state", srv->getNetworkState());
1054 callout_handle->setArgument("json_config", config);
1055 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1056
1057 HooksManager::callCallouts(Hooks.hooks_index_dhcp6_srv_configured_,
1058 *callout_handle);
1059
1060 // If next step is DROP, report a configuration error.
1061 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1062 string error;
1063 try {
1064 callout_handle->getArgument("error", error);
1065 } catch (NoSuchArgument const& ex) {
1066 error = "unknown error";
1067 }
1069 }
1070 }
1071
1072 // Apply multi threading settings.
1073 // @note These settings are applied/updated only if no errors occur while
1074 // applying the new configuration.
1075 // @todo This should be fixed.
1076 try {
1077 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1078 } catch (const std::exception& ex) {
1079 err << "Error applying multi threading settings: "
1080 << ex.what();
1082 }
1083
1084 return (answer);
1085}
1086
1089
1091 .arg(redactConfig(config)->str());
1092
1094
1095 if (!srv) {
1097 "Server object not initialized, can't process config.");
1098 return (no_srv);
1099 }
1100
1101 return (configureDhcp6Server(*srv, config, true));
1102}
1103
1105 uint16_t client_port)
1106 : Dhcpv6Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1107 if (getInstance()) {
1109 "There is another Dhcpv6Srv instance already.");
1110 }
1111 server_ = this; // remember this instance for later use in handlers
1112
1113 // TimerMgr uses IO service to run asynchronous timers.
1114 TimerMgr::instance()->setIOService(getIOService());
1115
1116 // CommandMgr uses IO service to run asynchronous socket operations.
1117 CommandMgr::instance().setIOService(getIOService());
1118
1119 // LeaseMgr uses IO service to run asynchronous timers.
1121
1122 // HostMgr uses IO service to run asynchronous timers.
1124
1125 // These are the commands always supported by the DHCPv6 server.
1126 // Please keep the list in alphabetic order.
1127 CommandMgr::instance().registerCommand("build-report",
1128 std::bind(&ControlledDhcpv6Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1129
1130 CommandMgr::instance().registerCommand("config-backend-pull",
1131 std::bind(&ControlledDhcpv6Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1132
1133 CommandMgr::instance().registerCommand("config-get",
1134 std::bind(&ControlledDhcpv6Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1135
1136 CommandMgr::instance().registerCommand("config-reload",
1137 std::bind(&ControlledDhcpv6Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1138
1139 CommandMgr::instance().registerCommand("config-test",
1140 std::bind(&ControlledDhcpv6Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1141
1142 CommandMgr::instance().registerCommand("config-write",
1143 std::bind(&ControlledDhcpv6Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1144
1145 CommandMgr::instance().registerCommand("dhcp-disable",
1146 std::bind(&ControlledDhcpv6Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1147
1148 CommandMgr::instance().registerCommand("dhcp-enable",
1149 std::bind(&ControlledDhcpv6Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1150
1151 CommandMgr::instance().registerCommand("leases-reclaim",
1152 std::bind(&ControlledDhcpv6Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1153
1154 CommandMgr::instance().registerCommand("server-tag-get",
1155 std::bind(&ControlledDhcpv6Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1156
1157 CommandMgr::instance().registerCommand("libreload",
1158 std::bind(&ControlledDhcpv6Srv::commandLibReloadHandler, this, ph::_1, ph::_2));
1159
1160 CommandMgr::instance().registerCommand("config-set",
1161 std::bind(&ControlledDhcpv6Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1162
1163 CommandMgr::instance().registerCommand("shutdown",
1164 std::bind(&ControlledDhcpv6Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1165
1166 CommandMgr::instance().registerCommand("status-get",
1167 std::bind(&ControlledDhcpv6Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1168
1169 CommandMgr::instance().registerCommand("version-get",
1170 std::bind(&ControlledDhcpv6Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1171
1172 // Register statistic related commands
1173 CommandMgr::instance().registerCommand("statistic-get",
1174 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1175
1176 CommandMgr::instance().registerCommand("statistic-get-all",
1177 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1178
1179 CommandMgr::instance().registerCommand("statistic-reset",
1180 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1181
1182 CommandMgr::instance().registerCommand("statistic-reset-all",
1183 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1184
1185 CommandMgr::instance().registerCommand("statistic-remove",
1186 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1187
1188 CommandMgr::instance().registerCommand("statistic-remove-all",
1189 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1190
1191 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1192 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1193
1194 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1195 std::bind(&ControlledDhcpv6Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1196
1197 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1198 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1199
1200 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1201 std::bind(&ControlledDhcpv6Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1202}
1203
1205 setExitValue(exit_value);
1206 getIOService()->stop(); // Stop ASIO transmissions
1207 shutdown(); // Initiate DHCPv6 shutdown procedure.
1208}
1209
1211 try {
1214 cleanup();
1215
1216 // The closure captures either a shared pointer (memory leak)
1217 // or a raw pointer (pointing to a deleted object).
1221
1222 timer_mgr_->unregisterTimers();
1223
1224 // Close the command socket (if it exists).
1225 CommandMgr::instance().closeCommandSocket();
1226
1227 // Deregister any registered commands (please keep in alphabetic order)
1228 CommandMgr::instance().deregisterCommand("build-report");
1229 CommandMgr::instance().deregisterCommand("config-backend-pull");
1230 CommandMgr::instance().deregisterCommand("config-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("libreload");
1239 CommandMgr::instance().deregisterCommand("server-tag-get");
1240 CommandMgr::instance().deregisterCommand("shutdown");
1241 CommandMgr::instance().deregisterCommand("statistic-get");
1242 CommandMgr::instance().deregisterCommand("statistic-get-all");
1243 CommandMgr::instance().deregisterCommand("statistic-remove");
1244 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1245 CommandMgr::instance().deregisterCommand("statistic-reset");
1246 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1247 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1248 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1249 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1250 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1251 CommandMgr::instance().deregisterCommand("status-get");
1252 CommandMgr::instance().deregisterCommand("version-get");
1253
1254 // LeaseMgr uses IO service to run asynchronous timers.
1256
1257 // HostMgr uses IO service to run asynchronous timers.
1259 } catch (...) {
1260 // Don't want to throw exceptions from the destructor. The server
1261 // is shutting down anyway.
1262 ;
1263 }
1264
1265 server_ = NULL; // forget this instance. There should be no callback anymore
1266 // at this stage anyway.
1267}
1268
1269void
1270ControlledDhcpv6Srv::reclaimExpiredLeases(const size_t max_leases,
1271 const uint16_t timeout,
1272 const bool remove_lease,
1273 const uint16_t max_unwarned_cycles) {
1274 try {
1275 server_->alloc_engine_->reclaimExpiredLeases6(max_leases, timeout,
1276 remove_lease,
1277 max_unwarned_cycles);
1278 } catch (const std::exception& ex) {
1280 .arg(ex.what());
1281 }
1282 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1284}
1285
1286void
1287ControlledDhcpv6Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1288 server_->alloc_engine_->deleteExpiredReclaimedLeases6(secs);
1289 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1291}
1292
1293bool
1294ControlledDhcpv6Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1295 if (!db_reconnect_ctl) {
1296 // This should never happen
1298 return (false);
1299 }
1300
1301 // Disable service until the connection is recovered.
1302 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1303 db_reconnect_ctl->alterServiceState()) {
1305 }
1306
1308
1309 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1310 // return false.
1311 if (!db_reconnect_ctl->retriesLeft() ||
1312 !db_reconnect_ctl->retryInterval()) {
1314 .arg(db_reconnect_ctl->retriesLeft())
1315 .arg(db_reconnect_ctl->retryInterval());
1316 if (db_reconnect_ctl->exitOnFailure()) {
1317 shutdownServer(EXIT_FAILURE);
1318 }
1319 return (false);
1320 }
1321
1322 return (true);
1323}
1324
1325bool
1326ControlledDhcpv6Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1327 if (!db_reconnect_ctl) {
1328 // This should never happen
1330 return (false);
1331 }
1332
1333 // Enable service after the connection is recovered.
1334 if (db_reconnect_ctl->alterServiceState()) {
1336 }
1337
1339
1340 db_reconnect_ctl->resetRetries();
1341
1342 return (true);
1343}
1344
1345bool
1346ControlledDhcpv6Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1347 if (!db_reconnect_ctl) {
1348 // This should never happen
1350 return (false);
1351 }
1352
1354 .arg(db_reconnect_ctl->maxRetries());
1355
1356 if (db_reconnect_ctl->exitOnFailure()) {
1357 shutdownServer(EXIT_FAILURE);
1358 }
1359
1360 return (true);
1361}
1362
1363void
1364ControlledDhcpv6Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1365 if (!reconnect_ctl) {
1366 // This should never happen
1368 return;
1369 }
1370
1372 .arg(reconnect_ctl->maxRetries());
1373
1374 if (reconnect_ctl->exitOnFailure()) {
1375 shutdownServer(EXIT_FAILURE);
1376 }
1377}
1378
1379void
1380ControlledDhcpv6Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1381 boost::shared_ptr<unsigned> failure_count) {
1382 // stop thread pool (if running)
1384
1385 try {
1386 // Fetch any configuration backend updates since our last fetch.
1387 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1388 CBControlDHCPv6::FetchMode::FETCH_UPDATE);
1389 (*failure_count) = 0;
1390
1391 } catch (const std::exception& ex) {
1393 .arg(ex.what());
1394
1395 // We allow at most 10 consecutive failures after which we stop
1396 // making further attempts to fetch the configuration updates.
1397 // Let's return without re-scheduling the timer.
1398 if (++(*failure_count) > 10) {
1401 return;
1402 }
1403 }
1404
1405 // Reschedule the timer to fetch new updates or re-try if
1406 // the previous attempt resulted in an error.
1407 if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
1408 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
1409 }
1410}
1411
1412} // namespace dhcp
1413} // 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 ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:241
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:291
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:286
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.
static const std::string FLUSH_RECLAIMED_TIMER_NAME
Name of the timer for flushing reclaimed leases.
static const std::string RECLAIM_EXPIRED_TIMER_NAME
Name of the timer for reclaiming expired leases.
static OpenSocketsFailedCallback open_sockets_failed_callback_
Optional callback function to invoke if all retries of the opening sockets fail.
Definition: cfg_iface.h:361
void rollback()
Removes staging configuration.
Definition: cfgmgr.cc:120
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition: cfgmgr.cc:167
void commit()
Commits the staging configuration.
Definition: cfgmgr.cc:90
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
static void apply(data::ConstElementPtr value)
apply multi threading configuration
Controlled version of the DHCPv6 server.
void init(const std::string &config_file)
Initializes the server.
void cleanup()
Performs cleanup, immediately before termination.
isc::data::ConstElementPtr checkConfig(isc::data::ConstElementPtr new_config)
Configuration checker.
static isc::data::ConstElementPtr processConfig(isc::data::ConstElementPtr new_config)
Configuration processor.
virtual ~ControlledDhcpv6Srv()
Destructor.
static isc::data::ConstElementPtr processCommand(const std::string &command, isc::data::ConstElementPtr args)
Command processor.
virtual void shutdownServer(int exit_value)
Initiates shutdown procedure for the whole DHCPv6 server.
static ControlledDhcpv6Srv * getInstance()
Returns pointer to the sole instance of Dhcpv6Srv.
isc::data::ConstElementPtr loadConfigFile(const std::string &file_name)
Configure DHCPv6 server using the configuration file specified.
ControlledDhcpv6Srv(uint16_t server_port=DHCP6_SERVER_PORT, uint16_t client_port=0)
Constructor.
virtual void open()
Open communication socket.
Definition: dhcp6to4_ipc.cc:39
static Dhcp6to4Ipc & instance()
Returns pointer to the sole instance of Dhcp6to4Ipc.
Definition: dhcp6to4_ipc.cc:34
DHCPv6 server service.
Definition: dhcp6_srv.h:66
void shutdown() override
Instructs the server to shut down.
Definition: dhcp6_srv.cc:304
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
Definition: dhcp6_srv.h:1184
uint16_t getServerPort() const
Get UDP port on which server should listen.
Definition: dhcp6_srv.h:216
OptionPtr serverid_
Server DUID (to be sent in server-identifier option)
Definition: dhcp6_srv.h:1166
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:1192
CBControlDHCPv6Ptr getCBControl() const
Returns an object which controls access to the configuration backends.
Definition: dhcp6_srv.h:124
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
Definition: dhcp6_srv.cc:4251
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
Definition: dhcp6_srv.h:110
bool inTestMode() const
Checks if the server is running in unit test mode.
Definition: dhcp6_srv.h:105
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
Definition: dhcp6_srv.cc:4215
static void setIOService(const isc::asiolink::IOServicePtr &io_service)
Sets IO service to be used by the Host Manager.
Definition: host_mgr.h:638
static void create()
Creates new instance of the HostMgr.
Definition: host_mgr.cc:43
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
static void destroy()
Destroy lease manager.
static void setIOService(const isc::asiolink::IOServicePtr &io_service)
Sets IO service to be used by the Lease Manager.
Definition: lease_mgr.h:786
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition: libdhcp++.cc:238
Origin
Origin of the network state transition.
Definition: network_state.h:84
@ USER_COMMAND
The network state is being altered by a user command.
@ DB_CONNECTION
The network state is being altered by the DB connection recovery mechanics.
@ HA_COMMAND
The network state is being altered by a HA internal command.
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:449
std::string getConfigFile() const
Returns config file name.
Definition: daemon.cc:105
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:229
isc::asiolink::IOSignalSetPtr signal_set_
A pointer to the object installing custom signal handlers.
Definition: daemon.h:257
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition: daemon.h:263
void setExitValue(int value)
Sets the exit value.
Definition: daemon.h:227
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition: daemon.cc:257
Statistics Manager class.
RAII class creating a critical section.
This file contains several functions and constants that are used for handling commands and responses ...
@ D6O_SERVERID
Definition: dhcp6.h:22
Defines the Dhcp6to4Ipc class.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
isc::data::ConstElementPtr statisticSetMaxSampleCountAllHandler(const isc::data::ConstElementPtr &params)
Handles statistic-sample-count-set-all command.
isc::data::ConstElementPtr statisticSetMaxSampleAgeAllHandler(const isc::data::ConstElementPtr &params)
Handles statistic-sample-age-set-all command.
uint32_t getMaxSampleCountDefault() const
Get default count limit.
const StatsDuration & getMaxSampleAgeDefault() const
Get default duration limit.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_FATAL(LOGGER, MESSAGE)
Macro to conveniently test fatal output and log it.
Definition: macros.h:38
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
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:27
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
@ error
Definition: db_log.h:115
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
isc::data::ConstElementPtr configureDhcp6Server(Dhcpv6Srv &server, isc::data::ConstElementPtr config_set, bool check_only)
Configures DHCPv6 server.
const isc::log::MessageID DHCP6_DB_RECONNECT_SUCCEEDED
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:20
const int DBG_DHCP6_COMMAND
Debug level used to log receiving commands.
Definition: dhcp6_log.h:28
const isc::log::MessageID DHCP6_CB_PERIODIC_FETCH_UPDATES_FAIL
const isc::log::MessageID DHCP6_RECLAIM_EXPIRED_LEASES_FAIL
const isc::log::MessageID DHCP6_OPEN_SOCKETS_FAILED
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
Definition: srv_config.h:1165
const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION_SUCCESS
const isc::log::MessageID DHCP6_CB_ON_DEMAND_FETCH_UPDATES_FAIL
const isc::log::MessageID DHCP6_COMMAND_RECEIVED
const isc::log::MessageID DHCP6_CB_PERIODIC_FETCH_UPDATES_RETRIES_EXHAUSTED
const isc::log::MessageID DHCP6_NOT_RUNNING
const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION_FAIL
const isc::log::MessageID DHCP6_CONFIG_UNSUPPORTED_OBJECT
const isc::log::MessageID DHCP6_CONFIG_UNRECOVERABLE_ERROR
const isc::log::MessageID DHCP6_CONFIG_RECEIVED
const isc::log::MessageID DHCP6_DB_RECONNECT_DISABLED
const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION
const isc::log::MessageID DHCP6_DB_RECONNECT_LOST_CONNECTION
const isc::log::MessageID DHCP6_HOOKS_LIBS_RELOAD_FAIL
isc::log::Logger dhcp6_logger(DHCP6_APP_LOGGER_NAME)
Base logger for DHCPv6 server.
Definition: dhcp6_log.h:88
const isc::log::MessageID DHCP6_MULTI_THREADING_INFO
const isc::log::MessageID DHCP6_DB_RECONNECT_FAILED
const isc::log::MessageID DHCP6_CONFIG_PACKET_QUEUE
std::vector< HookLibInfo > HookLibsCollection
A storage for information about hook libraries.
Definition: libinfo.h:31
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
long toSeconds(const StatsDuration &dur)
Returns the number of seconds in a duration.
Definition: observation.h:45
Definition: edns.h:19
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.