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