Kea 2.5.8
ctrl_dhcp4_srv.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
12#include <cc/data.h>
13#include <config/command_mgr.h>
15#include <dhcp/libdhcp++.h>
17#include <dhcp4/dhcp4_log.h>
18#include <dhcp4/dhcp4to6_ipc.h>
23#include <dhcpsrv/cfgmgr.h>
24#include <dhcpsrv/db_type.h>
25#include <dhcpsrv/host_mgr.h>
27#include <hooks/hooks.h>
28#include <hooks/hooks_manager.h>
30#include <stats/stats_mgr.h>
31#include <util/encode/encode.h>
33
34#include <signal.h>
35
36#include <sstream>
37
38using namespace isc::asiolink;
39using namespace isc::config;
40using namespace isc::data;
41using namespace isc::db;
42using namespace isc::dhcp;
43using namespace isc::hooks;
44using namespace isc::stats;
45using namespace isc::util;
46using namespace std;
47namespace ph = std::placeholders;
48
49namespace {
50
52struct CtrlDhcp4Hooks {
53 int hooks_index_dhcp4_srv_configured_;
54
56 CtrlDhcp4Hooks() {
57 hooks_index_dhcp4_srv_configured_ = HooksManager::registerHook("dhcp4_srv_configured");
58 }
59
60};
61
62// Declare a Hooks object. As this is outside any function or method, it
63// will be instantiated (and the constructor run) when the module is loaded.
64// As a result, the hook indexes will be defined before any method in this
65// module is called.
66CtrlDhcp4Hooks Hooks;
67
77void signalHandler(int signo) {
78 // SIGHUP signals a request to reconfigure the server.
79 if (signo == SIGHUP) {
82 } else if ((signo == SIGTERM) || (signo == SIGINT)) {
85 }
86}
87
88}
89
90namespace isc {
91namespace dhcp {
92
93ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = NULL;
94
95void
96ControlledDhcpv4Srv::init(const std::string& file_name) {
97 // Keep the call timestamp.
98 start_ = boost::posix_time::second_clock::universal_time();
99
100 // Configure the server using JSON file.
101 ConstElementPtr result = loadConfigFile(file_name);
102
103 int rcode;
104 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
105 if (rcode != CONTROL_RESULT_SUCCESS) {
106 string reason = comment ? comment->stringValue() :
107 "no details available";
108 isc_throw(isc::BadValue, reason);
109 }
110
111 // We don't need to call openActiveSockets() or startD2() as these
112 // methods are called in processConfig() which is called by
113 // processCommand("config-set", ...)
114
115 // Set signal handlers. When the SIGHUP is received by the process
116 // the server reconfiguration will be triggered. When SIGTERM or
117 // SIGINT will be received, the server will start shutting down.
118 signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
119
120 signal_set_->add(SIGINT);
121 signal_set_->add(SIGHUP);
122 signal_set_->add(SIGTERM);
123}
124
126 signal_set_.reset();
127 getIOService()->poll();
128}
129
131ControlledDhcpv4Srv::loadConfigFile(const std::string& file_name) {
132 // This is a configuration backend implementation that reads the
133 // configuration from a JSON file.
134
137
138 // Basic sanity check: file name must not be empty.
139 try {
140 if (file_name.empty()) {
141 // Basic sanity check: file name must not be empty.
142 isc_throw(isc::BadValue, "JSON configuration file not specified."
143 " Please use -c command line option.");
144 }
145
146 // Read contents of the file and parse it as JSON
147 Parser4Context parser;
148 json = parser.parseFile(file_name, Parser4Context::PARSER_DHCP4);
149 if (!json) {
150 isc_throw(isc::BadValue, "no configuration found");
151 }
152
153 // Let's do sanity check before we call json->get() which
154 // works only for map.
155 if (json->getType() != isc::data::Element::map) {
156 isc_throw(isc::BadValue, "Configuration file is expected to be "
157 "a map, i.e., start with { and end with } and contain "
158 "at least an entry called 'Dhcp4' that itself is a map. "
159 << file_name
160 << " is a valid JSON, but its top element is not a map."
161 " Did you forget to add { } around your configuration?");
162 }
163
164 // Use parsed JSON structures to configure the server
165 result = ControlledDhcpv4Srv::processCommand("config-set", json);
166 if (!result) {
167 // Undetermined status of the configuration. This should never
168 // happen, but as the configureDhcp4Server returns a pointer, it is
169 // theoretically possible that it will return NULL.
170 isc_throw(isc::BadValue, "undefined result of "
171 "processCommand(\"config-set\", json)");
172 }
173
174 // Now check is the returned result is successful (rcode=0) or not
175 // (see @ref isc::config::parseAnswer).
176 int rcode;
177 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
178 if (rcode != CONTROL_RESULT_SUCCESS) {
179 string reason = comment ? comment->stringValue() :
180 "no details available";
181 isc_throw(isc::BadValue, reason);
182 }
183 } catch (const std::exception& ex) {
184 // If configuration failed at any stage, we drop the staging
185 // configuration and continue to use the previous one.
187
189 .arg(file_name).arg(ex.what());
190 isc_throw(isc::BadValue, "configuration error using file '"
191 << file_name << "': " << ex.what());
192 }
193
195 .arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
196 .arg(MultiThreadingMgr::instance().getThreadPoolSize())
197 .arg(MultiThreadingMgr::instance().getPacketQueueSize());
198
199 return (result);
200}
201
203ControlledDhcpv4Srv::commandShutdownHandler(const string&, ConstElementPtr args) {
206 return (createAnswer(CONTROL_RESULT_ERROR, "Shutdown failure."));
207 }
208
209 int exit_value = 0;
210 if (args) {
211 // @todo Should we go ahead and shutdown even if the args are invalid?
212 if (args->getType() != Element::map) {
213 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
214 }
215
216 ConstElementPtr param = args->get("exit-value");
217 if (param) {
218 if (param->getType() != Element::integer) {
220 "parameter 'exit-value' is not an integer"));
221 }
222
223 exit_value = param->intValue();
224 }
225 }
226
228 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
229}
230
232ControlledDhcpv4Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
233 LOG_WARN(dhcp4_logger, DHCP4_DEPRECATED).arg("libreload command");
234
235 // stop thread pool (if running)
237
238 // Clear the packet queue.
240
241 try {
245 static_cast<void>(HooksManager::unloadLibraries());
247 bool multi_threading_enabled = true;
248 uint32_t thread_count = 0;
249 uint32_t queue_size = 0;
250 CfgMultiThreading::extract(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading(),
251 multi_threading_enabled, thread_count, queue_size);
252 bool status = HooksManager::loadLibraries(loaded, multi_threading_enabled);
253 if (!status) {
254 isc_throw(Unexpected, "Failed to reload hooks libraries "
255 "(WARNING: libreload is deprecated).");
256 }
257 } catch (const std::exception& ex) {
260 return (answer);
261 }
263 "Hooks libraries successfully reloaded "
264 "(WARNING: libreload is deprecated).");
265 return (answer);
266}
267
269ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
270 ConstElementPtr /*args*/) {
271 // Get configuration file name.
273 try {
275 auto result = loadConfigFile(file);
277 return (result);
278 } catch (const std::exception& ex) {
279 // Log the unsuccessful reconfiguration. The reason for failure
280 // should be already logged. Don't rethrow an exception so as
281 // the server keeps working.
283 .arg(file);
285 "Config reload failed: " + string(ex.what())));
286 }
287}
288
290ControlledDhcpv4Srv::commandConfigGetHandler(const string&,
291 ConstElementPtr /*args*/) {
292 ElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
293 string hash = BaseCommandMgr::getHash(config);
294 config->set("hash", Element::create(hash));
295
296 return (createAnswer(CONTROL_RESULT_SUCCESS, config));
297}
298
300ControlledDhcpv4Srv::commandConfigHashGetHandler(const string&,
301 ConstElementPtr /*args*/) {
302 ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
303
304 string hash = BaseCommandMgr::getHash(config);
305
307 params->set("hash", Element::create(hash));
308 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
309}
310
312ControlledDhcpv4Srv::commandConfigWriteHandler(const string&,
313 ConstElementPtr args) {
314 string filename;
315
316 if (args) {
317 if (args->getType() != Element::map) {
318 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
319 }
320 ConstElementPtr filename_param = args->get("filename");
321 if (filename_param) {
322 if (filename_param->getType() != Element::string) {
324 "passed parameter 'filename' is not a string"));
325 }
326 filename = filename_param->stringValue();
327 }
328 }
329
330 if (filename.empty()) {
331 // filename parameter was not specified, so let's use whatever we remember
332 // from the command-line
333 filename = getConfigFile();
334 }
335
336 if (filename.empty()) {
337 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
338 "Please specify filename explicitly."));
339 }
340
341 // Ok, it's time to write the file.
342 size_t size = 0;
343 try {
344 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
345 size = writeConfigFile(filename, cfg);
346 } catch (const isc::Exception& ex) {
347 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during write-config: ")
348 + ex.what()));
349 }
350 if (size == 0) {
351 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
352 + filename));
353 }
354
355 // Ok, it's time to return the successful response.
357 params->set("size", Element::create(static_cast<long long>(size)));
358 params->set("filename", Element::create(filename));
359
360 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
361 + filename + " successful", params));
362}
363
365ControlledDhcpv4Srv::commandConfigSetHandler(const string&,
366 ConstElementPtr args) {
367 const int status_code = CONTROL_RESULT_ERROR;
368 ConstElementPtr dhcp4;
369 string message;
370
371 // Command arguments are expected to be:
372 // { "Dhcp4": { ... } }
373 if (!args) {
374 message = "Missing mandatory 'arguments' parameter.";
375 } else {
376 dhcp4 = args->get("Dhcp4");
377 if (!dhcp4) {
378 message = "Missing mandatory 'Dhcp4' parameter.";
379 } else if (dhcp4->getType() != Element::map) {
380 message = "'Dhcp4' parameter expected to be a map.";
381 }
382 }
383
384 // Check unsupported objects.
385 if (message.empty()) {
386 for (auto const& obj : args->mapValue()) {
387 const string& obj_name = obj.first;
388 if (obj_name != "Dhcp4") {
390 .arg(obj_name);
391 if (message.empty()) {
392 message = "Unsupported '" + obj_name + "' parameter";
393 } else {
394 message += " (and '" + obj_name + "')";
395 }
396 }
397 }
398 if (!message.empty()) {
399 message += ".";
400 }
401 }
402
403 if (!message.empty()) {
404 // Something is amiss with arguments, return a failure response.
405 ConstElementPtr result = isc::config::createAnswer(status_code,
406 message);
407 return (result);
408 }
409
410 // stop thread pool (if running)
412
413 // We are starting the configuration process so we should remove any
414 // staging configuration that has been created during previous
415 // configuration attempts.
417
418 // Parse the logger configuration explicitly into the staging config.
419 // Note this does not alter the current loggers, they remain in
420 // effect until we apply the logging config below. If no logging
421 // is supplied logging will revert to default logging.
422 Daemon::configureLogger(dhcp4, CfgMgr::instance().getStagingCfg());
423
424 // Let's apply the new logging. We do it early, so we'll be able to print
425 // out what exactly is wrong with the new config in case of problems.
426 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
427
428 // Now we configure the server proper.
429 ConstElementPtr result = processConfig(dhcp4);
430
431 // If the configuration parsed successfully, apply the new logger
432 // configuration and the commit the new configuration. We apply
433 // the logging first in case there's a configuration failure.
434 int rcode = 0;
435 isc::config::parseAnswer(rcode, result);
436 if (rcode == CONTROL_RESULT_SUCCESS) {
437 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
438
439 // Use new configuration.
441 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
442 // Ok, we applied the logging from the upcoming configuration, but
443 // there were problems with the config. As such, we need to back off
444 // and revert to the previous logging configuration. This is not done if
445 // sequence == 0, because that would mean always reverting to stdout by
446 // default, and it is arguably more helpful to have the error in a
447 // potential file or syslog configured in the upcoming configuration.
448 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
449
450 // Not initial configuration so someone can believe we reverted
451 // to the previous configuration. It is not the case so be clear
452 // about this.
454 }
455
457 try {
458 // Handle events registered by hooks using external IOService objects.
460 } catch (const std::exception& ex) {
461 std::ostringstream err;
462 err << "Error initializing hooks: "
463 << ex.what();
465 }
466
467 return (result);
468}
469
471ControlledDhcpv4Srv::commandConfigTestHandler(const string&,
472 ConstElementPtr args) {
473 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
474 ConstElementPtr dhcp4;
475 string message;
476
477 // Command arguments are expected to be:
478 // { "Dhcp4": { ... } }
479 if (!args) {
480 message = "Missing mandatory 'arguments' parameter.";
481 } else {
482 dhcp4 = args->get("Dhcp4");
483 if (!dhcp4) {
484 message = "Missing mandatory 'Dhcp4' parameter.";
485 } else if (dhcp4->getType() != Element::map) {
486 message = "'Dhcp4' parameter expected to be a map.";
487 }
488 }
489
490 // Check unsupported objects.
491 if (message.empty()) {
492 for (auto const& obj : args->mapValue()) {
493 const string& obj_name = obj.first;
494 if (obj_name != "Dhcp4") {
496 .arg(obj_name);
497 if (message.empty()) {
498 message = "Unsupported '" + obj_name + "' parameter";
499 } else {
500 message += " (and '" + obj_name + "')";
501 }
502 }
503 }
504 if (!message.empty()) {
505 message += ".";
506 }
507 }
508
509 if (!message.empty()) {
510 // Something is amiss with arguments, return a failure response.
511 ConstElementPtr result = isc::config::createAnswer(status_code,
512 message);
513 return (result);
514 }
515
516 // stop thread pool (if running)
518
519 // We are starting the configuration process so we should remove any
520 // staging configuration that has been created during previous
521 // configuration attempts.
523
524 // Now we check the server proper.
525 return (checkConfig(dhcp4));
526}
527
529ControlledDhcpv4Srv::commandDhcpDisableHandler(const std::string&,
530 ConstElementPtr args) {
531 std::ostringstream message;
532 int64_t max_period = 0;
533 std::string origin;
534
535 // If the args map does not contain 'origin' parameter, the default type
536 // will be used (user command).
537 auto type = NetworkState::USER_COMMAND;
538
539 // Parse arguments to see if the 'max-period' or 'origin' parameters have
540 // been specified.
541 if (args) {
542 // Arguments must be a map.
543 if (args->getType() != Element::map) {
544 message << "arguments for the 'dhcp-disable' command must be a map";
545
546 } else {
547 ConstElementPtr max_period_element = args->get("max-period");
548 // max-period is optional.
549 if (max_period_element) {
550 // It must be an integer, if specified.
551 if (max_period_element->getType() != Element::integer) {
552 message << "'max-period' argument must be a number";
553
554 } else {
555 // It must be positive integer.
556 max_period = max_period_element->intValue();
557 if (max_period <= 0) {
558 message << "'max-period' must be positive integer";
559 }
560 }
561 }
562 ConstElementPtr origin_element = args->get("origin");
563 // The 'origin' parameter is optional.
564 if (origin_element) {
565 switch (origin_element->getType()) {
566 case Element::string:
567 origin = origin_element->stringValue();
568 if (origin == "ha-partner") {
570 } else if (origin != "user") {
571 if (origin.empty()) {
572 origin = "(empty string)";
573 }
574 message << "invalid value used for 'origin' parameter: "
575 << origin;
576 }
577 break;
578 case Element::integer:
579 type = origin_element->intValue();
580 break;
581 default:
582 // It must be a string or a number, if specified.
583 message << "'origin' argument must be a string or a number";
584 }
585 }
586 }
587 }
588
589 // No error occurred, so let's disable the service.
590 if (message.tellp() == 0) {
591 message << "DHCPv4 service disabled";
592 if (max_period > 0) {
593 message << " for " << max_period << " seconds";
594
595 // The user specified that the DHCP service should resume not
596 // later than in max-period seconds. If the 'dhcp-enable' command
597 // is not sent, the DHCP service will resume automatically.
598 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
599 type);
600 }
601 network_state_->disableService(type);
602
603 // Success.
604 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
605 }
606
607 // Failure.
608 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
609}
610
612ControlledDhcpv4Srv::commandDhcpEnableHandler(const std::string&,
613 ConstElementPtr args) {
614 std::ostringstream message;
615 std::string origin;
616
617 // If the args map does not contain 'origin' parameter, the default type
618 // will be used (user command).
619 auto type = NetworkState::USER_COMMAND;
620
621 // Parse arguments to see if the 'origin' parameter has been specified.
622 if (args) {
623 // Arguments must be a map.
624 if (args->getType() != Element::map) {
625 message << "arguments for the 'dhcp-enable' command must be a map";
626
627 } else {
628 ConstElementPtr origin_element = args->get("origin");
629 // The 'origin' parameter is optional.
630 if (origin_element) {
631 switch (origin_element->getType()) {
632 case Element::string:
633 origin = origin_element->stringValue();
634 if (origin == "ha-partner") {
636 } else if (origin != "user") {
637 if (origin.empty()) {
638 origin = "(empty string)";
639 }
640 message << "invalid value used for 'origin' parameter: "
641 << origin;
642 }
643 break;
644 case Element::integer:
645 type = origin_element->intValue();
646 break;
647 default:
648 // It must be a string or a number, if specified.
649 message << "'origin' argument must be a string or a number";
650 }
651 }
652 }
653 }
654
655 // No error occurred, so let's enable the service.
656 if (message.tellp() == 0) {
657 network_state_->enableService(type);
658
659 // Success.
661 "DHCP service successfully enabled"));
662 }
663
664 // Failure.
665 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
666}
667
669ControlledDhcpv4Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
671 ElementPtr arguments = Element::createMap();
672 arguments->set("extended", extended);
675 arguments);
676 return (answer);
677}
678
680ControlledDhcpv4Srv::commandBuildReportHandler(const string&,
682 ConstElementPtr answer =
684 return (answer);
685}
686
688ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
689 ConstElementPtr args) {
690 int status_code = CONTROL_RESULT_ERROR;
691 string message;
692
693 // args must be { "remove": <bool> }
694 if (!args) {
695 message = "Missing mandatory 'remove' parameter.";
696 } else {
697 ConstElementPtr remove_name = args->get("remove");
698 if (!remove_name) {
699 message = "Missing mandatory 'remove' parameter.";
700 } else if (remove_name->getType() != Element::boolean) {
701 message = "'remove' parameter expected to be a boolean.";
702 } else {
703 bool remove_lease = remove_name->boolValue();
704 server_->alloc_engine_->reclaimExpiredLeases4(0, 0, remove_lease);
705 status_code = 0;
706 message = "Reclamation of expired leases is complete.";
707 }
708 }
709 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
710 return (answer);
711}
712
714ControlledDhcpv4Srv::commandServerTagGetHandler(const std::string&,
716 const std::string& tag =
717 CfgMgr::instance().getCurrentCfg()->getServerTag();
718 ElementPtr response = Element::createMap();
719 response->set("server-tag", Element::create(tag));
720
721 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
722}
723
725ControlledDhcpv4Srv::commandConfigBackendPullHandler(const std::string&,
727 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
728 if (!ctl_info) {
729 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
730 }
731
732 // stop thread pool (if running)
734
735 // Reschedule the periodic CB fetch.
736 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
737 TimerMgr::instance()->cancel("Dhcp4CBFetchTimer");
738 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
739 }
740
741 // Code from cbFetchUpdates.
742 // The configuration to use is the current one because this is called
743 // after the configuration manager commit.
744 try {
745 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
747 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
748 } catch (const std::exception& ex) {
750 .arg(ex.what());
752 "On demand configuration update failed: " +
753 string(ex.what())));
754 }
756 "On demand configuration update successful."));
757}
758
760ControlledDhcpv4Srv::commandStatusGetHandler(const string&,
761 ConstElementPtr /*args*/) {
763 status->set("pid", Element::create(static_cast<int>(getpid())));
764
765 auto now = boost::posix_time::second_clock::universal_time();
766 // Sanity check: start_ is always initialized.
767 if (!start_.is_not_a_date_time()) {
768 auto uptime = now - start_;
769 status->set("uptime", Element::create(uptime.total_seconds()));
770 }
771
772 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
773 if (!last_commit.is_not_a_date_time()) {
774 auto reload = now - last_commit;
775 status->set("reload", Element::create(reload.total_seconds()));
776 }
777
778 auto& mt_mgr = MultiThreadingMgr::instance();
779 if (mt_mgr.getMode()) {
780 status->set("multi-threading-enabled", Element::create(true));
781 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
782 MultiThreadingMgr::instance().getThreadPoolSize())));
783 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
784 MultiThreadingMgr::instance().getPacketQueueSize())));
785 ElementPtr queue_stats = Element::createList();
786 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
787 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
788 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
789 status->set("packet-queue-statistics", queue_stats);
790
791 } else {
792 status->set("multi-threading-enabled", Element::create(false));
793 }
794
795 // Iterate through the interfaces and get all the errors.
796 ElementPtr socket_errors(Element::createList());
797 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
798 for (std::string const& error : interface->getErrors()) {
799 socket_errors->add(Element::create(error));
800 }
801 }
802
803 // Abstract the information from all sockets into a single status.
805 if (socket_errors->empty()) {
806 sockets->set("status", Element::create("ready"));
807 } else {
808 ReconnectCtlPtr const reconnect_ctl(
809 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
810 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
811 sockets->set("status", Element::create("retrying"));
812 } else {
813 sockets->set("status", Element::create("failed"));
814 }
815 sockets->set("errors", socket_errors);
816 }
817 status->set("sockets", sockets);
818
819 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
820}
821
823ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
824 ConstElementPtr args) {
825 StatsMgr& stats_mgr = StatsMgr::instance();
827 // Update the default parameter.
828 long max_samples = stats_mgr.getMaxSampleCountDefault();
829 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
830 "statistic-default-sample-count", Element::create(max_samples));
831 return (answer);
832}
833
835ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
836 ConstElementPtr args) {
837 StatsMgr& stats_mgr = StatsMgr::instance();
839 // Update the default parameter.
840 auto duration = stats_mgr.getMaxSampleAgeDefault();
841 long max_age = toSeconds(duration);
842 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
843 "statistic-default-sample-age", Element::create(max_age));
844 return (answer);
845}
846
849 ConstElementPtr args) {
850 string txt = args ? args->str() : "(none)";
851
853 .arg(command).arg(txt);
854
856
857 if (!srv) {
859 "Server object not initialized, so can't process command '" +
860 command + "', arguments: '" + txt + "'.");
861 return (no_srv);
862 }
863
864 try {
865 if (command == "shutdown") {
866 return (srv->commandShutdownHandler(command, args));
867
868 } else if (command == "libreload") {
869 return (srv->commandLibReloadHandler(command, args));
870
871 } else if (command == "config-reload") {
872 return (srv->commandConfigReloadHandler(command, args));
873
874 } else if (command == "config-set") {
875 return (srv->commandConfigSetHandler(command, args));
876
877 } else if (command == "config-get") {
878 return (srv->commandConfigGetHandler(command, args));
879
880 } else if (command == "config-hash-get") {
881 return (srv->commandConfigHashGetHandler(command, args));
882
883 } else if (command == "config-test") {
884 return (srv->commandConfigTestHandler(command, args));
885
886 } else if (command == "dhcp-disable") {
887 return (srv->commandDhcpDisableHandler(command, args));
888
889 } else if (command == "dhcp-enable") {
890 return (srv->commandDhcpEnableHandler(command, args));
891
892 } else if (command == "version-get") {
893 return (srv->commandVersionGetHandler(command, args));
894
895 } else if (command == "build-report") {
896 return (srv->commandBuildReportHandler(command, args));
897
898 } else if (command == "leases-reclaim") {
899 return (srv->commandLeasesReclaimHandler(command, args));
900
901 } else if (command == "config-write") {
902 return (srv->commandConfigWriteHandler(command, args));
903
904 } else if (command == "server-tag-get") {
905 return (srv->commandServerTagGetHandler(command, args));
906
907 } else if (command == "config-backend-pull") {
908 return (srv->commandConfigBackendPullHandler(command, args));
909
910 } else if (command == "status-get") {
911 return (srv->commandStatusGetHandler(command, args));
912 }
913
914 return (isc::config::createAnswer(CONTROL_RESULT_ERROR, "Unrecognized command:"
915 + command));
916
917 } catch (const isc::Exception& ex) {
918 return (isc::config::createAnswer(CONTROL_RESULT_ERROR, "Error while processing command '"
919 + command + "': " + ex.what() +
920 ", params: '" + txt + "'"));
921 }
922}
923
927
928 // Allow DB reconnect on startup. The database connection parameters specify
929 // respective details.
931
932 // Single stream instance used in all error clauses
933 std::ostringstream err;
934
935 if (!srv) {
936 err << "Server object not initialized, can't process config.";
938 }
939
941 .arg(srv->redactConfig(config)->str());
942
943 ConstElementPtr answer = configureDhcp4Server(*srv, config);
944
945 // Check that configuration was successful. If not, do not reopen sockets
946 // and don't bother with DDNS stuff.
947 try {
948 int rcode = 0;
949 isc::config::parseAnswer(rcode, answer);
950 if (rcode != 0) {
951 return (answer);
952 }
953 } catch (const std::exception& ex) {
954 err << "Failed to process configuration:" << ex.what();
956 }
957
958 // Re-open lease and host database with new parameters.
959 try {
961 std::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, ph::_1);
962
964 std::bind(&ControlledDhcpv4Srv::dbRecoveredCallback, srv, ph::_1);
965
967 std::bind(&ControlledDhcpv4Srv::dbFailedCallback, srv, ph::_1);
968
969 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
970 string params = "universe=4";
971 if (cfg_db->getExtendedInfoTablesEnabled()) {
972 params += " extended-info-tables=true";
973 }
974 cfg_db->setAppendedParameters(params);
975 cfg_db->createManagers();
976 // Reset counters related to connections as all managers have been recreated.
977 srv->getNetworkState()->resetForDbConnection();
978
979 } catch (const std::exception& ex) {
980 err << "Unable to open database: " << ex.what();
982 }
983
984 // Server will start DDNS communications if its enabled.
985 try {
986 srv->startD2();
987 } catch (const std::exception& ex) {
988 err << "Error starting DHCP_DDNS client after server reconfiguration: "
989 << ex.what();
991 }
992
993 // Setup DHCPv4-over-DHCPv6 IPC
994 try {
996 } catch (const std::exception& ex) {
997 err << "error starting DHCPv4-over-DHCPv6 IPC "
998 " after server reconfiguration: " << ex.what();
1000 }
1001
1002 // Configure DHCP packet queueing
1003 try {
1005 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
1006 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
1008 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
1009 }
1010
1011 } catch (const std::exception& ex) {
1012 err << "Error setting packet queue controls after server reconfiguration: "
1013 << ex.what();
1015 }
1016
1017 // Configure a callback to shut down the server when the bind socket
1018 // attempts exceeded.
1020 std::bind(&ControlledDhcpv4Srv::openSocketsFailedCallback, srv, ph::_1);
1021
1022 // Configuration may change active interfaces. Therefore, we have to reopen
1023 // sockets according to new configuration. It is possible that this
1024 // operation will fail for some interfaces but the openSockets function
1025 // guards against exceptions and invokes a callback function to
1026 // log warnings. Since we allow that this fails for some interfaces there
1027 // is no need to rollback configuration if socket fails to open on any
1028 // of the interfaces.
1029 CfgMgr::instance().getStagingCfg()->getCfgIface()->
1030 openSockets(AF_INET, srv->getServerPort(),
1032
1033 // Install the timers for handling leases reclamation.
1034 try {
1035 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
1036 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
1037 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
1038 server_);
1039
1040 } catch (const std::exception& ex) {
1041 err << "unable to setup timers for periodically running the"
1042 " reclamation of the expired leases: "
1043 << ex.what() << ".";
1045 }
1046
1047 // Setup config backend polling, if configured for it.
1048 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
1049 if (ctl_info) {
1050 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
1051 // Only schedule the CB fetch timer if the fetch wait time is greater
1052 // than 0.
1053 if (fetch_time > 0) {
1054 // When we run unit tests, we want to use milliseconds unit for the
1055 // specified interval. Otherwise, we use seconds. Note that using
1056 // milliseconds as a unit in unit tests prevents us from waiting 1
1057 // second on more before the timer goes off. Instead, we wait one
1058 // millisecond which significantly reduces the test time.
1059 if (!server_->inTestMode()) {
1060 fetch_time = 1000 * fetch_time;
1061 }
1062
1063 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1065 registerTimer("Dhcp4CBFetchTimer",
1066 std::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
1067 server_, CfgMgr::instance().getStagingCfg(),
1068 failure_count),
1069 fetch_time,
1071 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1072 }
1073 }
1074
1075 // Finally, we can commit runtime option definitions in libdhcp++. This is
1076 // exception free.
1078
1079 auto notify_libraries = ControlledDhcpv4Srv::finishConfigHookLibraries(config);
1080 if (notify_libraries) {
1081 return (notify_libraries);
1082 }
1083
1084
1085 // Initialize the allocators. If the user selected a Free Lease Queue Allocator
1086 // for any of the subnets, the server will now populate free leases to the queue.
1087 // It may take a while!
1088 try {
1089 CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->initAllocatorsAfterConfigure();
1090
1091 } catch (const std::exception& ex) {
1092 err << "Error initializing the lease allocators: "
1093 << ex.what();
1095 }
1096
1097 // Apply multi threading settings.
1098 // @note These settings are applied/updated only if no errors occur while
1099 // applying the new configuration.
1100 // @todo This should be fixed.
1101 try {
1102 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1103 } catch (const std::exception& ex) {
1104 err << "Error applying multi threading settings: "
1105 << ex.what();
1107 }
1108
1109 return (answer);
1110}
1111
1115 // This hook point notifies hooks libraries that the configuration of the
1116 // DHCPv4 server has completed. It provides the hook library with the pointer
1117 // to the common IO service object, new server configuration in the JSON
1118 // format and with the pointer to the configuration storage where the
1119 // parsed configuration is stored.
1120 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp4_srv_configured_)) {
1122
1123 callout_handle->setArgument("io_context", srv->getIOService());
1124 callout_handle->setArgument("network_state", srv->getNetworkState());
1125 callout_handle->setArgument("json_config", config);
1126 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1127
1128 HooksManager::callCallouts(Hooks.hooks_index_dhcp4_srv_configured_,
1129 *callout_handle);
1130
1131 // If next step is DROP, report a configuration error.
1132 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1133 string error;
1134 try {
1135 callout_handle->getArgument("error", error);
1136 } catch (NoSuchArgument const& ex) {
1137 error = "unknown error";
1138 }
1140 }
1141 }
1142
1143 return (ConstElementPtr());
1144}
1145
1149
1150 if (!srv) {
1152 "Server object not initialized, can't process config.");
1153 return (no_srv);
1154 }
1155
1157 .arg(srv->redactConfig(config)->str());
1158
1159 return (configureDhcp4Server(*srv, config, true));
1160}
1161
1162ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
1163 uint16_t client_port /*= 0*/)
1164 : Dhcpv4Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1165 if (getInstance()) {
1167 "There is another Dhcpv4Srv instance already.");
1168 }
1169 server_ = this; // remember this instance for later use in handlers
1170
1171 // ProcessSpawn uses IO service to handle signal set events.
1173
1174 // TimerMgr uses IO service to run asynchronous timers.
1175 TimerMgr::instance()->setIOService(getIOService());
1176
1177 // CommandMgr uses IO service to run asynchronous socket operations.
1179
1180 // DatabaseConnection uses IO service to run asynchronous timers.
1182
1183 // These are the commands always supported by the DHCPv4 server.
1184 // Please keep the list in alphabetic order.
1185 CommandMgr::instance().registerCommand("build-report",
1186 std::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1187
1188 CommandMgr::instance().registerCommand("config-backend-pull",
1189 std::bind(&ControlledDhcpv4Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1190
1192 std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1193
1194 CommandMgr::instance().registerCommand("config-hash-get",
1195 std::bind(&ControlledDhcpv4Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1196
1197 CommandMgr::instance().registerCommand("config-reload",
1198 std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1199
1201 std::bind(&ControlledDhcpv4Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1202
1203 CommandMgr::instance().registerCommand("config-test",
1204 std::bind(&ControlledDhcpv4Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1205
1206 CommandMgr::instance().registerCommand("config-write",
1207 std::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1208
1209 CommandMgr::instance().registerCommand("dhcp-enable",
1210 std::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1211
1212 CommandMgr::instance().registerCommand("dhcp-disable",
1213 std::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1214
1216 std::bind(&ControlledDhcpv4Srv::commandLibReloadHandler, this, ph::_1, ph::_2));
1217
1218 CommandMgr::instance().registerCommand("leases-reclaim",
1219 std::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1220
1221 CommandMgr::instance().registerCommand("server-tag-get",
1222 std::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1223
1225 std::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1226
1228 std::bind(&ControlledDhcpv4Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1229
1230 CommandMgr::instance().registerCommand("version-get",
1231 std::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1232
1233 // Register statistic related commands
1234 CommandMgr::instance().registerCommand("statistic-get",
1235 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1236
1237 CommandMgr::instance().registerCommand("statistic-reset",
1238 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1239
1240 CommandMgr::instance().registerCommand("statistic-remove",
1241 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1242
1243 CommandMgr::instance().registerCommand("statistic-get-all",
1244 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1245
1246 CommandMgr::instance().registerCommand("statistic-reset-all",
1247 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1248
1249 CommandMgr::instance().registerCommand("statistic-remove-all",
1250 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1251
1252 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1253 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1254
1255 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1256 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1257
1258 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1259 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1260
1261 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1262 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1263}
1264
1266 setExitValue(exit_value);
1267 getIOService()->stop(); // Stop ASIO transmissions
1268 shutdown(); // Initiate DHCPv4 shutdown procedure.
1269}
1270
1272 try {
1273 MultiThreadingMgr::instance().apply(false, 0, 0);
1276
1277 // The closure captures either a shared pointer (memory leak)
1278 // or a raw pointer (pointing to a deleted object).
1282
1283 timer_mgr_->unregisterTimers();
1284
1285 cleanup();
1286
1287 // Close the command socket (if it exists).
1289
1290 // Deregister any registered commands (please keep in alphabetic order)
1291 CommandMgr::instance().deregisterCommand("build-report");
1292 CommandMgr::instance().deregisterCommand("config-backend-pull");
1294 CommandMgr::instance().deregisterCommand("config-hash-get");
1295 CommandMgr::instance().deregisterCommand("config-reload");
1297 CommandMgr::instance().deregisterCommand("config-test");
1298 CommandMgr::instance().deregisterCommand("config-write");
1299 CommandMgr::instance().deregisterCommand("dhcp-disable");
1300 CommandMgr::instance().deregisterCommand("dhcp-enable");
1301 CommandMgr::instance().deregisterCommand("leases-reclaim");
1303 CommandMgr::instance().deregisterCommand("server-tag-get");
1305 CommandMgr::instance().deregisterCommand("statistic-get");
1306 CommandMgr::instance().deregisterCommand("statistic-get-all");
1307 CommandMgr::instance().deregisterCommand("statistic-remove");
1308 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1309 CommandMgr::instance().deregisterCommand("statistic-reset");
1310 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1311 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1312 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1313 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1314 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1316 CommandMgr::instance().deregisterCommand("version-get");
1317
1318 // Reset DatabaseConnection IO service.
1320 } catch (...) {
1321 // Don't want to throw exceptions from the destructor. The server
1322 // is shutting down anyway.
1323 }
1324
1325 server_ = NULL; // forget this instance. There should be no callback anymore
1326 // at this stage anyway.
1327}
1328
1329void
1330ControlledDhcpv4Srv::reclaimExpiredLeases(const size_t max_leases,
1331 const uint16_t timeout,
1332 const bool remove_lease,
1333 const uint16_t max_unwarned_cycles) {
1334 try {
1335 server_->alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
1336 remove_lease,
1337 max_unwarned_cycles);
1338 } catch (const std::exception& ex) {
1340 .arg(ex.what());
1341 }
1342 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1344}
1345
1346void
1347ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1348 server_->alloc_engine_->deleteExpiredReclaimedLeases4(secs);
1349 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1351}
1352
1353bool
1354ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1355 if (!db_reconnect_ctl) {
1356 // This should never happen
1358 return (false);
1359 }
1360
1361 // Disable service until the connection is recovered.
1362 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1363 db_reconnect_ctl->alterServiceState()) {
1365 }
1366
1368
1369 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1370 // return false.
1371 if (!db_reconnect_ctl->retriesLeft() ||
1372 !db_reconnect_ctl->retryInterval()) {
1374 .arg(db_reconnect_ctl->retriesLeft())
1375 .arg(db_reconnect_ctl->retryInterval());
1376 if (db_reconnect_ctl->exitOnFailure()) {
1377 shutdownServer(EXIT_FAILURE);
1378 }
1379 return (false);
1380 }
1381
1382 return (true);
1383}
1384
1385bool
1386ControlledDhcpv4Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1387 if (!db_reconnect_ctl) {
1388 // This should never happen
1390 return (false);
1391 }
1392
1393 // Enable service after the connection is recovered.
1394 if (db_reconnect_ctl->alterServiceState()) {
1396 }
1397
1399
1400 db_reconnect_ctl->resetRetries();
1401
1402 return (true);
1403}
1404
1405bool
1406ControlledDhcpv4Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1407 if (!db_reconnect_ctl) {
1408 // This should never happen
1410 return (false);
1411 }
1412
1414 .arg(db_reconnect_ctl->maxRetries());
1415
1416 if (db_reconnect_ctl->exitOnFailure()) {
1417 shutdownServer(EXIT_FAILURE);
1418 }
1419
1420 return (true);
1421}
1422
1423void
1424ControlledDhcpv4Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1425 if (!reconnect_ctl) {
1426 // This should never happen
1428 return;
1429 }
1430
1432 .arg(reconnect_ctl->maxRetries());
1433
1434 if (reconnect_ctl->exitOnFailure()) {
1435 shutdownServer(EXIT_FAILURE);
1436 }
1437}
1438
1439void
1440ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1441 boost::shared_ptr<unsigned> failure_count) {
1442 // stop thread pool (if running)
1444
1445 try {
1446 // Fetch any configuration backend updates since our last fetch.
1447 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1449 (*failure_count) = 0;
1450
1451 } catch (const std::exception& ex) {
1453 .arg(ex.what());
1454
1455 // We allow at most 10 consecutive failures after which we stop
1456 // making further attempts to fetch the configuration updates.
1457 // Let's return without re-scheduling the timer.
1458 if (++(*failure_count) > 10) {
1461 return;
1462 }
1463 }
1464
1465 // Reschedule the timer to fetch new updates or re-try if
1466 // the previous attempt resulted in an error.
1467 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1468 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1469 }
1470}
1471
1472} // namespace dhcp
1473} // 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.
A generic exception that is thrown when an unexpected error condition occurs.
void registerCommand(const std::string &cmd, CommandHandler handler)
Registers specified command handler for a given command.
static std::string getHash(const isc::data::ConstElementPtr &config)
returns a hash of a given Element structure
void deregisterCommand(const std::string &cmd)
Deregisters specified command handler.
void closeCommandSocket()
Shuts down any open control sockets.
Definition: command_mgr.cc:624
static CommandMgr & instance()
CommandMgr is a singleton class.
Definition: command_mgr.cc:646
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the command manager.
Definition: command_mgr.cc:652
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:249
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:304
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:299
static void setIOService(const isc::asiolink::IOServicePtr &io_service)
Sets IO service to be used by the database backends.
static DbCallback db_recovered_callback_
Optional callback function to invoke if an opened connection recovery succeeded.
static DbCallback db_failed_callback_
Optional callback function to invoke if an opened connection recovery failed.
static DbCallback db_lost_callback_
Optional callback function to invoke if an opened connection is lost.
RAII class to enable DB reconnect retries on server startup.
static const std::string FLUSH_RECLAIMED_TIMER_NAME
Name of the timer for flushing reclaimed leases.
static const std::string RECLAIM_EXPIRED_TIMER_NAME
Name of the timer for reclaiming expired leases.
static OpenSocketsFailedCallback open_sockets_failed_callback_
Optional callback function to invoke if all retries of the opening sockets fail.
Definition: cfg_iface.h:361
void rollback()
Removes staging configuration.
Definition: cfgmgr.cc:120
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition: cfgmgr.cc:167
void commit()
Commits the staging configuration.
Definition: cfgmgr.cc:90
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
static void apply(data::ConstElementPtr value)
apply multi threading configuration
static void extract(data::ConstElementPtr value, bool &enabled, uint32_t &thread_count, uint32_t &queue_size)
Extract multi-threading parameters from a given configuration.
Controlled version of the DHCPv4 server.
virtual ~ControlledDhcpv4Srv()
Destructor.
static isc::data::ConstElementPtr finishConfigHookLibraries(isc::data::ConstElementPtr config)
Configuration checker for hook libraries.
isc::data::ConstElementPtr loadConfigFile(const std::string &file_name)
Configure DHCPv4 server using the configuration file specified.
void cleanup()
Performs cleanup, immediately before termination.
static isc::data::ConstElementPtr processCommand(const std::string &command, isc::data::ConstElementPtr args)
Command processor.
ControlledDhcpv4Srv(uint16_t server_port=DHCP4_SERVER_PORT, uint16_t client_port=0)
Constructor.
static isc::data::ConstElementPtr checkConfig(isc::data::ConstElementPtr config)
Configuration checker.
void init(const std::string &config_file)
Initializes the server.
static isc::data::ConstElementPtr processConfig(isc::data::ConstElementPtr config)
Configuration processor.
static ControlledDhcpv4Srv * getInstance()
Returns pointer to the sole instance of Dhcpv4Srv.
virtual void shutdownServer(int exit_value)
Initiates shutdown procedure for the whole DHCPv4 server.
static Dhcp4to6Ipc & instance()
Returns pointer to the sole instance of Dhcp4to6Ipc.
Definition: dhcp4to6_ipc.cc:32
virtual void open()
Open communication socket.
Definition: dhcp4to6_ipc.cc:37
DHCPv4 server service.
Definition: dhcp4_srv.h:253
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
Definition: dhcp4_srv.cc:4796
void shutdown() override
Instructs the server to shut down.
Definition: dhcp4_srv.cc:715
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
Definition: dhcp4_srv.h:304
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
Definition: dhcp4_srv.h:1221
bool inTestMode() const
Checks if the server is running in unit test mode.
Definition: dhcp4_srv.h:299
NetworkStatePtr & getNetworkState()
Returns pointer to the network state used by the server.
Definition: dhcp4_srv.h:309
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
Definition: dhcp4_srv.cc:4830
bool useBroadcast() const
Return bool value indicating that broadcast flags should be set on sockets.
Definition: dhcp4_srv.h:450
NetworkStatePtr network_state_
Holds information about disabled DHCP service and/or disabled subnet/network scopes.
Definition: dhcp4_srv.h:1228
uint16_t getServerPort() const
Get UDP port on which server should listen.
Definition: dhcp4_srv.h:442
CBControlDHCPv4Ptr getCBControl() const
Returns an object which controls access to the configuration backends.
Definition: dhcp4_srv.h:318
static void create()
Creates new instance of the HostMgr.
Definition: host_mgr.cc:52
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:54
static void destroy()
Destroy lease manager.
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition: libdhcp++.cc:242
static const unsigned int DB_CONNECTION
The network state is being altered by the DB connection recovery mechanics.
static const unsigned int USER_COMMAND
Origin of the network state transition.
Definition: network_state.h:90
static const unsigned int HA_REMOTE_COMMAND
The network state is being altered by a "dhcp-disable" or "dhcp-enable" command sent by a HA partner.
Evaluation context, an interface to the expression evaluation.
isc::data::ElementPtr parseFile(const std::string &filename, ParserType parser_type)
Run the parser on the file specified.
@ PARSER_DHCP4
This parser will parse the content as Dhcp4 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 bool unloadLibraries()
Unload libraries.
static bool loadLibraries(const HookLibsCollection &libraries, bool multi_threading_enabled=false)
Load and reload libraries.
static boost::shared_ptr< CalloutHandle > createCalloutHandle()
Return callout handle.
static void callCallouts(int index, CalloutHandle &handle)
Calls the callouts for a given hook.
static HookLibsCollection getLibraryInfo()
Return list of loaded libraries with its parameters.
static void prepareUnloadLibraries()
Prepare the unloading of libraries.
std::string getConfigFile() const
Returns config file name.
Definition: daemon.cc:104
virtual size_t writeConfigFile(const std::string &config_file, isc::data::ConstElementPtr cfg=isc::data::ConstElementPtr()) const
Writes current configuration to specified file.
Definition: daemon.cc:228
isc::asiolink::IOSignalSetPtr signal_set_
A pointer to the object installing custom signal handlers.
Definition: daemon.h:257
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition: daemon.h:263
void setExitValue(int value)
Sets the exit value.
Definition: daemon.h:227
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition: daemon.cc:256
Statistics Manager class.
static StatsMgr & instance()
Statistics Manager accessor method.
RAII class creating a critical section.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
ThreadPool< std::function< void()> > & getThreadPool()
Get the dhcp thread pool.
void apply(bool enabled, uint32_t thread_count, uint32_t queue_size)
Apply the multi-threading related settings.
This file contains several functions and constants that are used for handling commands and responses ...
Contains declarations for loggers used by the DHCPv4 server component.
Defines the Dhcp4o6Ipc class.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
isc::data::ConstElementPtr statisticSetMaxSampleCountAllHandler(const isc::data::ConstElementPtr &params)
Handles statistic-sample-count-set-all command.
static isc::data::ConstElementPtr statisticResetHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-reset command.
static isc::data::ConstElementPtr statisticGetAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-get-all command.
static isc::data::ConstElementPtr statisticRemoveHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-remove command.
static isc::data::ConstElementPtr statisticGetHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-get command.
isc::data::ConstElementPtr statisticSetMaxSampleAgeAllHandler(const isc::data::ConstElementPtr &params)
Handles statistic-sample-age-set-all command.
static isc::data::ConstElementPtr statisticResetAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-reset-all command.
static isc::data::ConstElementPtr statisticSetMaxSampleAgeHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-sample-age-set command.
static isc::data::ConstElementPtr statisticRemoveAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-remove-all command.
static isc::data::ConstElementPtr statisticSetMaxSampleCountHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-sample-count-set command.
uint32_t getMaxSampleCountDefault() const
Get default count limit.
const StatsDuration & getMaxSampleAgeDefault() const
Get default duration limit.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_FATAL(LOGGER, MESSAGE)
Macro to conveniently test fatal output and log it.
Definition: macros.h:38
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
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 DHCP4_NOT_RUNNING
const isc::log::MessageID DHCP4_DYNAMIC_RECONFIGURATION_FAIL
const isc::log::MessageID DHCP4_CONFIG_RECEIVED
const isc::log::MessageID DHCP4_DYNAMIC_RECONFIGURATION_SUCCESS
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
const isc::log::MessageID DHCP4_DB_RECONNECT_NO_DB_CTL
const isc::log::MessageID DHCP4_CB_PERIODIC_FETCH_UPDATES_RETRIES_EXHAUSTED
const isc::log::MessageID DHCP4_CONFIG_PACKET_QUEUE
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
Definition: srv_config.h:1267
const isc::log::MessageID DHCP4_CB_ON_DEMAND_FETCH_UPDATES_FAIL
const isc::log::MessageID DHCP4_CONFIG_LOAD_FAIL
const int DBG_DHCP4_COMMAND
Debug level used to log receiving commands.
Definition: dhcp4_log.h:30
const isc::log::MessageID DHCP4_HOOKS_LIBS_RELOAD_FAIL
const isc::log::MessageID DHCP4_DB_RECONNECT_DISABLED
const isc::log::MessageID DHCP4_CONFIG_UNRECOVERABLE_ERROR
const isc::log::MessageID DHCP4_DEPRECATED
const isc::log::MessageID DHCP4_DB_RECONNECT_SUCCEEDED
isc::data::ConstElementPtr configureDhcp4Server(Dhcpv4Srv &server, isc::data::ConstElementPtr config_set, bool check_only, bool extra_checks)
Configure DHCPv4 server (Dhcpv4Srv) with a set of configuration values.
const isc::log::MessageID DHCP4_COMMAND_RECEIVED
const isc::log::MessageID DHCP4_MULTI_THREADING_INFO
const isc::log::MessageID DHCP4_OPEN_SOCKETS_NO_RECONNECT_CTL
isc::log::Logger dhcp4_logger(DHCP4_APP_LOGGER_NAME)
Base logger for DHCPv4 server.
Definition: dhcp4_log.h:90
const isc::log::MessageID DHCP4_DB_RECONNECT_FAILED
const isc::log::MessageID DHCP4_OPEN_SOCKETS_FAILED
const isc::log::MessageID DHCP4_DYNAMIC_RECONFIGURATION
const isc::log::MessageID DHCP4_RECLAIM_EXPIRED_LEASES_FAIL
const isc::log::MessageID DHCP4_CONFIG_UNSUPPORTED_OBJECT
const isc::log::MessageID DHCP4_CB_PERIODIC_FETCH_UPDATES_FAIL
const isc::log::MessageID DHCP4_DB_RECONNECT_LOST_CONNECTION
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:49
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.
void reset()
reset the thread pool stopping threads and clearing the internal queue
Definition: thread_pool.h:60