Kea 2.7.0
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) {
80 CommandMgr::instance().processCommand(createCommand("config-reload"));
81 } else if ((signo == SIGTERM) || (signo == SIGINT)) {
82 CommandMgr::instance().processCommand(createCommand("shutdown"));
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 // Set signal handlers. When the SIGHUP is received by the process
110 // the server reconfiguration will be triggered. When SIGTERM or
111 // SIGINT will be received, the server will start shutting down.
112 signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
113
114 signal_set_->add(SIGINT);
115 signal_set_->add(SIGHUP);
116 signal_set_->add(SIGTERM);
117}
118
120 signal_set_.reset();
121 getIOService()->poll();
122}
123
125ControlledDhcpv4Srv::loadConfigFile(const std::string& file_name) {
126 // This is a configuration backend implementation that reads the
127 // configuration from a JSON file.
128
131
132 // Basic sanity check: file name must not be empty.
133 try {
134 if (file_name.empty()) {
135 // Basic sanity check: file name must not be empty.
136 isc_throw(isc::BadValue, "JSON configuration file not specified."
137 " Please use -c command line option.");
138 }
139
140 // Read contents of the file and parse it as JSON
141 Parser4Context parser;
142 json = parser.parseFile(file_name, Parser4Context::PARSER_DHCP4);
143 if (!json) {
144 isc_throw(isc::BadValue, "no configuration found");
145 }
146
147 // Let's do sanity check before we call json->get() which
148 // works only for map.
149 if (json->getType() != isc::data::Element::map) {
150 isc_throw(isc::BadValue, "Configuration file is expected to be "
151 "a map, i.e., start with { and end with } and contain "
152 "at least an entry called 'Dhcp4' that itself is a map. "
153 << file_name
154 << " is a valid JSON, but its top element is not a map."
155 " Did you forget to add { } around your configuration?");
156 }
157
158 // Use parsed JSON structures to configure the server
159 result = CommandMgr::instance().processCommand(createCommand("config-set", json));
160 if (!result) {
161 // Undetermined status of the configuration. This should never
162 // happen, but as the configureDhcp4Server returns a pointer, it is
163 // theoretically possible that it will return NULL.
164 isc_throw(isc::BadValue, "undefined result of "
165 "process command \"config-set\"");
166 }
167
168 // Now check is the returned result is successful (rcode=0) or not
169 // (see @ref isc::config::parseAnswer).
170 int rcode;
171 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
172 if (rcode != CONTROL_RESULT_SUCCESS) {
173 string reason = comment ? comment->stringValue() :
174 "no details available";
175 isc_throw(isc::BadValue, reason);
176 }
177 } catch (const std::exception& ex) {
178 // If configuration failed at any stage, we drop the staging
179 // configuration and continue to use the previous one.
180 CfgMgr::instance().rollback();
181
183 .arg(file_name).arg(ex.what());
184 isc_throw(isc::BadValue, "configuration error using file '"
185 << file_name << "': " << ex.what());
186 }
187
189 .arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
190 .arg(MultiThreadingMgr::instance().getThreadPoolSize())
191 .arg(MultiThreadingMgr::instance().getPacketQueueSize());
192
193 return (result);
194}
195
197ControlledDhcpv4Srv::commandShutdownHandler(const string&, ConstElementPtr args) {
200 return (createAnswer(CONTROL_RESULT_ERROR, "Shutdown failure."));
201 }
202
203 int exit_value = 0;
204 if (args) {
205 // @todo Should we go ahead and shutdown even if the args are invalid?
206 if (args->getType() != Element::map) {
207 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
208 }
209
210 ConstElementPtr param = args->get("exit-value");
211 if (param) {
212 if (param->getType() != Element::integer) {
214 "parameter 'exit-value' is not an integer"));
215 }
216
217 exit_value = param->intValue();
218 }
219 }
220
221 ControlledDhcpv4Srv::getInstance()->shutdownServer(exit_value);
222 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
223}
224
226ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
227 ConstElementPtr /*args*/) {
228 // Get configuration file name.
229 string file = ControlledDhcpv4Srv::getInstance()->getConfigFile();
230 try {
232 auto result = loadConfigFile(file);
234 return (result);
235 } catch (const std::exception& ex) {
236 // Log the unsuccessful reconfiguration. The reason for failure
237 // should be already logged. Don't rethrow an exception so as
238 // the server keeps working.
240 .arg(file);
242 "Config reload failed: " + string(ex.what())));
243 }
244}
245
247ControlledDhcpv4Srv::commandConfigGetHandler(const string&,
248 ConstElementPtr /*args*/) {
249 ElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
250 string hash = BaseCommandMgr::getHash(config);
251 config->set("hash", Element::create(hash));
252
253 return (createAnswer(CONTROL_RESULT_SUCCESS, config));
254}
255
257ControlledDhcpv4Srv::commandConfigHashGetHandler(const string&,
258 ConstElementPtr /*args*/) {
259 ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
260
261 string hash = BaseCommandMgr::getHash(config);
262
264 params->set("hash", Element::create(hash));
265 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
266}
267
269ControlledDhcpv4Srv::commandConfigWriteHandler(const string&,
270 ConstElementPtr args) {
271 string filename;
272
273 if (args) {
274 if (args->getType() != Element::map) {
275 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
276 }
277 ConstElementPtr filename_param = args->get("filename");
278 if (filename_param) {
279 if (filename_param->getType() != Element::string) {
281 "passed parameter 'filename' is not a string"));
282 }
283 filename = filename_param->stringValue();
284 }
285 }
286
287 if (filename.empty()) {
288 // filename parameter was not specified, so let's use whatever we remember
289 // from the command-line
290 filename = getConfigFile();
291 }
292
293 if (filename.empty()) {
294 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
295 "Please specify filename explicitly."));
296 }
297
298 // Ok, it's time to write the file.
299 size_t size = 0;
300 try {
301 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
302 size = writeConfigFile(filename, cfg);
303 } catch (const isc::Exception& ex) {
304 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during write-config: ")
305 + ex.what()));
306 }
307 if (size == 0) {
308 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
309 + filename));
310 }
311
312 // Ok, it's time to return the successful response.
314 params->set("size", Element::create(static_cast<long long>(size)));
315 params->set("filename", Element::create(filename));
316
317 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
318 + filename + " successful", params));
319}
320
322ControlledDhcpv4Srv::commandConfigSetHandler(const string&,
323 ConstElementPtr args) {
324 const int status_code = CONTROL_RESULT_ERROR;
325 ConstElementPtr dhcp4;
326 string message;
327
328 // Command arguments are expected to be:
329 // { "Dhcp4": { ... } }
330 if (!args) {
331 message = "Missing mandatory 'arguments' parameter.";
332 } else {
333 dhcp4 = args->get("Dhcp4");
334 if (!dhcp4) {
335 message = "Missing mandatory 'Dhcp4' parameter.";
336 } else if (dhcp4->getType() != Element::map) {
337 message = "'Dhcp4' parameter expected to be a map.";
338 }
339 }
340
341 // Check unsupported objects.
342 if (message.empty()) {
343 for (auto const& obj : args->mapValue()) {
344 const string& obj_name = obj.first;
345 if (obj_name != "Dhcp4") {
347 .arg(obj_name);
348 if (message.empty()) {
349 message = "Unsupported '" + obj_name + "' parameter";
350 } else {
351 message += " (and '" + obj_name + "')";
352 }
353 }
354 }
355 if (!message.empty()) {
356 message += ".";
357 }
358 }
359
360 if (!message.empty()) {
361 // Something is amiss with arguments, return a failure response.
362 ConstElementPtr result = isc::config::createAnswer(status_code,
363 message);
364 return (result);
365 }
366
367 // stop thread pool (if running)
369
370 // We are starting the configuration process so we should remove any
371 // staging configuration that has been created during previous
372 // configuration attempts.
373 CfgMgr::instance().rollback();
374
375 // Parse the logger configuration explicitly into the staging config.
376 // Note this does not alter the current loggers, they remain in
377 // effect until we apply the logging config below. If no logging
378 // is supplied logging will revert to default logging.
379 Daemon::configureLogger(dhcp4, CfgMgr::instance().getStagingCfg());
380
381 // Let's apply the new logging. We do it early, so we'll be able to print
382 // out what exactly is wrong with the new config in case of problems.
383 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
384
385 // Now we configure the server proper.
386 ConstElementPtr result = processConfig(dhcp4);
387
388 // If the configuration parsed successfully, apply the new logger
389 // configuration and the commit the new configuration. We apply
390 // the logging first in case there's a configuration failure.
391 int rcode = 0;
392 isc::config::parseAnswer(rcode, result);
393 if (rcode == CONTROL_RESULT_SUCCESS) {
394 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
395
396 // Use new configuration.
397 CfgMgr::instance().commit();
398 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
399 // Ok, we applied the logging from the upcoming configuration, but
400 // there were problems with the config. As such, we need to back off
401 // and revert to the previous logging configuration. This is not done if
402 // sequence == 0, because that would mean always reverting to stdout by
403 // default, and it is arguably more helpful to have the error in a
404 // potential file or syslog configured in the upcoming configuration.
405 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
406
407 // Not initial configuration so someone can believe we reverted
408 // to the previous configuration. It is not the case so be clear
409 // about this.
411 }
412
414 try {
415 // Handle events registered by hooks using external IOService objects.
416 IOServiceMgr::instance().pollIOServices();
417 } catch (const std::exception& ex) {
418 std::ostringstream err;
419 err << "Error initializing hooks: "
420 << ex.what();
422 }
423
424 return (result);
425}
426
428ControlledDhcpv4Srv::commandConfigTestHandler(const string&,
429 ConstElementPtr args) {
430 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
431 ConstElementPtr dhcp4;
432 string message;
433
434 // Command arguments are expected to be:
435 // { "Dhcp4": { ... } }
436 if (!args) {
437 message = "Missing mandatory 'arguments' parameter.";
438 } else {
439 dhcp4 = args->get("Dhcp4");
440 if (!dhcp4) {
441 message = "Missing mandatory 'Dhcp4' parameter.";
442 } else if (dhcp4->getType() != Element::map) {
443 message = "'Dhcp4' parameter expected to be a map.";
444 }
445 }
446
447 // Check unsupported objects.
448 if (message.empty()) {
449 for (auto const& obj : args->mapValue()) {
450 const string& obj_name = obj.first;
451 if (obj_name != "Dhcp4") {
453 .arg(obj_name);
454 if (message.empty()) {
455 message = "Unsupported '" + obj_name + "' parameter";
456 } else {
457 message += " (and '" + obj_name + "')";
458 }
459 }
460 }
461 if (!message.empty()) {
462 message += ".";
463 }
464 }
465
466 if (!message.empty()) {
467 // Something is amiss with arguments, return a failure response.
468 ConstElementPtr result = isc::config::createAnswer(status_code,
469 message);
470 return (result);
471 }
472
473 // stop thread pool (if running)
475
476 // We are starting the configuration process so we should remove any
477 // staging configuration that has been created during previous
478 // configuration attempts.
479 CfgMgr::instance().rollback();
480
481 // Now we check the server proper.
482 return (checkConfig(dhcp4));
483}
484
486ControlledDhcpv4Srv::commandDhcpDisableHandler(const std::string&,
487 ConstElementPtr args) {
488 std::ostringstream message;
489 int64_t max_period = 0;
490 std::string origin;
491
492 // If the args map does not contain 'origin' parameter, the default type
493 // will be used (user command).
494 auto type = NetworkState::USER_COMMAND;
495
496 // Parse arguments to see if the 'max-period' or 'origin' parameters have
497 // been specified.
498 if (args) {
499 // Arguments must be a map.
500 if (args->getType() != Element::map) {
501 message << "arguments for the 'dhcp-disable' command must be a map";
502
503 } else {
504 ConstElementPtr max_period_element = args->get("max-period");
505 // max-period is optional.
506 if (max_period_element) {
507 // It must be an integer, if specified.
508 if (max_period_element->getType() != Element::integer) {
509 message << "'max-period' argument must be a number";
510
511 } else {
512 // It must be positive integer.
513 max_period = max_period_element->intValue();
514 if (max_period <= 0) {
515 message << "'max-period' must be positive integer";
516 }
517 }
518 }
519 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
520 // stable release. However, the 'origin' is kept for backward compatibility
521 // with Kea versions before 2.5.8. It is common to receive both parameters
522 // because HA hook library sends both in case the partner server hasn't been
523 // upgraded to the new version. The 'origin-id' takes precedence over the
524 // 'origin'.
525 ConstElementPtr origin_id_element = args->get("origin-id");
526 ConstElementPtr origin_element = args->get("origin");
527 // The 'origin-id' and 'origin' arguments are optional.
528 if (origin_id_element) {
529 if (origin_id_element->getType() == Element::integer) {
530 type = origin_id_element->intValue();
531 } else {
532 message << "'origin-id' argument must be a number";
533 }
534 } else if (origin_element) {
535 switch (origin_element->getType()) {
536 case Element::string:
537 origin = origin_element->stringValue();
538 if (origin == "ha-partner") {
540 } else if (origin != "user") {
541 if (origin.empty()) {
542 origin = "(empty string)";
543 }
544 message << "invalid value used for 'origin' parameter: "
545 << origin;
546 }
547 break;
548 case Element::integer:
549 type = origin_element->intValue();
550 break;
551 default:
552 // It must be a string or a number, if specified.
553 message << "'origin' argument must be a string or a number";
554 }
555 }
556 }
557 }
558
559 // No error occurred, so let's disable the service.
560 if (message.tellp() == 0) {
561 message << "DHCPv4 service disabled";
562 if (max_period > 0) {
563 message << " for " << max_period << " seconds";
564
565 // The user specified that the DHCP service should resume not
566 // later than in max-period seconds. If the 'dhcp-enable' command
567 // is not sent, the DHCP service will resume automatically.
568 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
569 type);
570 }
571 network_state_->disableService(type);
572
573 // Success.
574 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
575 }
576
577 // Failure.
578 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
579}
580
582ControlledDhcpv4Srv::commandDhcpEnableHandler(const std::string&,
583 ConstElementPtr args) {
584 std::ostringstream message;
585 std::string origin;
586
587 // If the args map does not contain 'origin' parameter, the default type
588 // will be used (user command).
589 auto type = NetworkState::USER_COMMAND;
590
591 // Parse arguments to see if the 'origin' parameter has been specified.
592 if (args) {
593 // Arguments must be a map.
594 if (args->getType() != Element::map) {
595 message << "arguments for the 'dhcp-enable' command must be a map";
596
597 } else {
598 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
599 // stable release. However, the 'origin' is kept for backward compatibility
600 // with Kea versions before 2.5.8. It is common to receive both parameters
601 // because HA hook library sends both in case the partner server hasn't been
602 // upgraded to the new version. The 'origin-id' takes precedence over the
603 // 'origin'.
604 ConstElementPtr origin_id_element = args->get("origin-id");
605 ConstElementPtr origin_element = args->get("origin");
606 // The 'origin-id' and 'origin' arguments are optional.
607 if (origin_id_element) {
608 if (origin_id_element->getType() == Element::integer) {
609 type = origin_id_element->intValue();
610 } else {
611 message << "'origin-id' argument must be a number";
612 }
613 } else if (origin_element) {
614 switch (origin_element->getType()) {
615 case Element::string:
616 origin = origin_element->stringValue();
617 if (origin == "ha-partner") {
619 } else if (origin != "user") {
620 if (origin.empty()) {
621 origin = "(empty string)";
622 }
623 message << "invalid value used for 'origin' parameter: "
624 << origin;
625 }
626 break;
627 case Element::integer:
628 type = origin_element->intValue();
629 break;
630 default:
631 // It must be a string or a number, if specified.
632 message << "'origin' argument must be a string or a number";
633 }
634 }
635 }
636 }
637
638 // No error occurred, so let's enable the service.
639 if (message.tellp() == 0) {
640 network_state_->enableService(type);
641
642 // Success.
644 "DHCP service successfully enabled"));
645 }
646
647 // Failure.
648 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
649}
650
652ControlledDhcpv4Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
654 ElementPtr arguments = Element::createMap();
655 arguments->set("extended", extended);
658 arguments);
659 return (answer);
660}
661
663ControlledDhcpv4Srv::commandBuildReportHandler(const string&,
665 ConstElementPtr answer =
667 return (answer);
668}
669
671ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
672 ConstElementPtr args) {
673 int status_code = CONTROL_RESULT_ERROR;
674 string message;
675
676 // args must be { "remove": <bool> }
677 if (!args) {
678 message = "Missing mandatory 'remove' parameter.";
679 } else {
680 ConstElementPtr remove_name = args->get("remove");
681 if (!remove_name) {
682 message = "Missing mandatory 'remove' parameter.";
683 } else if (remove_name->getType() != Element::boolean) {
684 message = "'remove' parameter expected to be a boolean.";
685 } else {
686 bool remove_lease = remove_name->boolValue();
687 server_->alloc_engine_->reclaimExpiredLeases4(0, 0, remove_lease);
688 status_code = 0;
689 message = "Reclamation of expired leases is complete.";
690 }
691 }
692 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
693 return (answer);
694}
695
697ControlledDhcpv4Srv::commandServerTagGetHandler(const std::string&,
699 const std::string& tag =
700 CfgMgr::instance().getCurrentCfg()->getServerTag();
701 ElementPtr response = Element::createMap();
702 response->set("server-tag", Element::create(tag));
703
704 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
705}
706
708ControlledDhcpv4Srv::commandConfigBackendPullHandler(const std::string&,
710 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
711 if (!ctl_info) {
712 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
713 }
714
715 // stop thread pool (if running)
717
718 // Reschedule the periodic CB fetch.
719 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
720 TimerMgr::instance()->cancel("Dhcp4CBFetchTimer");
721 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
722 }
723
724 // Code from cbFetchUpdates.
725 // The configuration to use is the current one because this is called
726 // after the configuration manager commit.
727 try {
728 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
730 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
731 } catch (const std::exception& ex) {
733 .arg(ex.what());
735 "On demand configuration update failed: " +
736 string(ex.what())));
737 }
739 "On demand configuration update successful."));
740}
741
743ControlledDhcpv4Srv::commandStatusGetHandler(const string&,
744 ConstElementPtr /*args*/) {
746 status->set("pid", Element::create(static_cast<int>(getpid())));
747
748 auto now = boost::posix_time::second_clock::universal_time();
749 // Sanity check: start_ is always initialized.
750 if (!start_.is_not_a_date_time()) {
751 auto uptime = now - start_;
752 status->set("uptime", Element::create(uptime.total_seconds()));
753 }
754
755 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
756 if (!last_commit.is_not_a_date_time()) {
757 auto reload = now - last_commit;
758 status->set("reload", Element::create(reload.total_seconds()));
759 }
760
761 auto& mt_mgr = MultiThreadingMgr::instance();
762 if (mt_mgr.getMode()) {
763 status->set("multi-threading-enabled", Element::create(true));
764 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
765 MultiThreadingMgr::instance().getThreadPoolSize())));
766 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
767 MultiThreadingMgr::instance().getPacketQueueSize())));
768 ElementPtr queue_stats = Element::createList();
769 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
770 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
771 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
772 status->set("packet-queue-statistics", queue_stats);
773
774 } else {
775 status->set("multi-threading-enabled", Element::create(false));
776 }
777
778 // Iterate through the interfaces and get all the errors.
779 ElementPtr socket_errors(Element::createList());
780 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
781 for (std::string const& error : interface->getErrors()) {
782 socket_errors->add(Element::create(error));
783 }
784 }
785
786 // Abstract the information from all sockets into a single status.
788 if (socket_errors->empty()) {
789 sockets->set("status", Element::create("ready"));
790 } else {
791 ReconnectCtlPtr const reconnect_ctl(
792 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
793 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
794 sockets->set("status", Element::create("retrying"));
795 } else {
796 sockets->set("status", Element::create("failed"));
797 }
798 sockets->set("errors", socket_errors);
799 }
800 status->set("sockets", sockets);
801
802 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
803}
804
806ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
807 ConstElementPtr args) {
808 StatsMgr& stats_mgr = StatsMgr::instance();
809 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleCountAllHandler(args);
810 // Update the default parameter.
811 long max_samples = stats_mgr.getMaxSampleCountDefault();
812 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
813 "statistic-default-sample-count", Element::create(max_samples));
814 return (answer);
815}
816
818ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
819 ConstElementPtr args) {
820 StatsMgr& stats_mgr = StatsMgr::instance();
821 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleAgeAllHandler(args);
822 // Update the default parameter.
823 auto duration = stats_mgr.getMaxSampleAgeDefault();
824 long max_age = toSeconds(duration);
825 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
826 "statistic-default-sample-age", Element::create(max_age));
827 return (answer);
828}
829
833
834 // Allow DB reconnect on startup. The database connection parameters specify
835 // respective details.
837
838 // Single stream instance used in all error clauses
839 std::ostringstream err;
840
841 if (!srv) {
842 err << "Server object not initialized, can't process config.";
844 }
845
847 .arg(srv->redactConfig(config)->str());
848
849 ConstElementPtr answer = configureDhcp4Server(*srv, config);
850
851 // Check that configuration was successful. If not, do not reopen sockets
852 // and don't bother with DDNS stuff.
853 try {
854 int rcode = 0;
855 isc::config::parseAnswer(rcode, answer);
856 if (rcode != 0) {
857 return (answer);
858 }
859 } catch (const std::exception& ex) {
860 err << "Failed to process configuration:" << ex.what();
862 }
863
864 // Re-open lease and host database with new parameters.
865 try {
867 std::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, ph::_1);
868
870 std::bind(&ControlledDhcpv4Srv::dbRecoveredCallback, srv, ph::_1);
871
873 std::bind(&ControlledDhcpv4Srv::dbFailedCallback, srv, ph::_1);
874
875 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
876 string params = "universe=4";
877 cfg_db->setAppendedParameters(params);
878 cfg_db->createManagers();
879 // Reset counters related to connections as all managers have been recreated.
880 srv->getNetworkState()->resetForDbConnection();
881
882 } catch (const std::exception& ex) {
883 err << "Unable to open database: " << ex.what();
885 }
886
887 // Server will start DDNS communications if its enabled.
888 try {
889 srv->startD2();
890 } catch (const std::exception& ex) {
891 err << "Error starting DHCP_DDNS client after server reconfiguration: "
892 << ex.what();
894 }
895
896 // Setup DHCPv4-over-DHCPv6 IPC
897 try {
898 Dhcp4to6Ipc::instance().open();
899 } catch (const std::exception& ex) {
900 err << "error starting DHCPv4-over-DHCPv6 IPC "
901 " after server reconfiguration: " << ex.what();
903 }
904
905 // Configure DHCP packet queueing
906 try {
908 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
909 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
911 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
912 }
913
914 } catch (const std::exception& ex) {
915 err << "Error setting packet queue controls after server reconfiguration: "
916 << ex.what();
918 }
919
920 // Configure a callback to shut down the server when the bind socket
921 // attempts exceeded.
923 std::bind(&ControlledDhcpv4Srv::openSocketsFailedCallback, srv, ph::_1);
924
925 // Configuration may change active interfaces. Therefore, we have to reopen
926 // sockets according to new configuration. It is possible that this
927 // operation will fail for some interfaces but the openSockets function
928 // guards against exceptions and invokes a callback function to
929 // log warnings. Since we allow that this fails for some interfaces there
930 // is no need to rollback configuration if socket fails to open on any
931 // of the interfaces.
932 CfgMgr::instance().getStagingCfg()->getCfgIface()->
933 openSockets(AF_INET, srv->getServerPort(),
935
936 // Install the timers for handling leases reclamation.
937 try {
938 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
939 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
940 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
941 server_);
942
943 } catch (const std::exception& ex) {
944 err << "unable to setup timers for periodically running the"
945 " reclamation of the expired leases: "
946 << ex.what() << ".";
948 }
949
950 // Setup config backend polling, if configured for it.
951 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
952 if (ctl_info) {
953 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
954 // Only schedule the CB fetch timer if the fetch wait time is greater
955 // than 0.
956 if (fetch_time > 0) {
957 // When we run unit tests, we want to use milliseconds unit for the
958 // specified interval. Otherwise, we use seconds. Note that using
959 // milliseconds as a unit in unit tests prevents us from waiting 1
960 // second on more before the timer goes off. Instead, we wait one
961 // millisecond which significantly reduces the test time.
962 if (!server_->inTestMode()) {
963 fetch_time = 1000 * fetch_time;
964 }
965
966 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
968 registerTimer("Dhcp4CBFetchTimer",
969 std::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
970 server_, CfgMgr::instance().getStagingCfg(),
971 failure_count),
972 fetch_time,
974 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
975 }
976 }
977
978 // Finally, we can commit runtime option definitions in libdhcp++. This is
979 // exception free.
981
982 auto notify_libraries = ControlledDhcpv4Srv::finishConfigHookLibraries(config);
983 if (notify_libraries) {
984 return (notify_libraries);
985 }
986
987
988 // Initialize the allocators. If the user selected a Free Lease Queue Allocator
989 // for any of the subnets, the server will now populate free leases to the queue.
990 // It may take a while!
991 try {
992 CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->initAllocatorsAfterConfigure();
993
994 } catch (const std::exception& ex) {
995 err << "Error initializing the lease allocators: "
996 << ex.what();
998 }
999
1000 // Apply multi threading settings.
1001 // @note These settings are applied/updated only if no errors occur while
1002 // applying the new configuration.
1003 // @todo This should be fixed.
1004 try {
1005 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1006 } catch (const std::exception& ex) {
1007 err << "Error applying multi threading settings: "
1008 << ex.what();
1010 }
1011
1012 return (answer);
1013}
1014
1018 // This hook point notifies hooks libraries that the configuration of the
1019 // DHCPv4 server has completed. It provides the hook library with the pointer
1020 // to the common IO service object, new server configuration in the JSON
1021 // format and with the pointer to the configuration storage where the
1022 // parsed configuration is stored.
1023 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp4_srv_configured_)) {
1025
1026 callout_handle->setArgument("io_context", srv->getIOService());
1027 callout_handle->setArgument("network_state", srv->getNetworkState());
1028 callout_handle->setArgument("json_config", config);
1029 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1030
1031 HooksManager::callCallouts(Hooks.hooks_index_dhcp4_srv_configured_,
1032 *callout_handle);
1033
1034 // If next step is DROP, report a configuration error.
1035 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1036 string error;
1037 try {
1038 callout_handle->getArgument("error", error);
1039 } catch (NoSuchArgument const& ex) {
1040 error = "unknown error";
1041 }
1043 }
1044 }
1045
1046 return (ConstElementPtr());
1047}
1048
1052
1053 if (!srv) {
1055 "Server object not initialized, can't process config.");
1056 return (no_srv);
1057 }
1058
1060 .arg(srv->redactConfig(config)->str());
1061
1062 return (configureDhcp4Server(*srv, config, true));
1063}
1064
1065ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
1066 uint16_t client_port /*= 0*/)
1067 : Dhcpv4Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1068 if (getInstance()) {
1070 "There is another Dhcpv4Srv instance already.");
1071 }
1072 server_ = this; // remember this instance for later use in handlers
1073
1074 // ProcessSpawn uses IO service to handle signal set events.
1076
1077 // TimerMgr uses IO service to run asynchronous timers.
1078 TimerMgr::instance()->setIOService(getIOService());
1079
1080 // CommandMgr uses IO service to run asynchronous socket operations.
1081 CommandMgr::instance().setIOService(getIOService());
1082
1083 // DatabaseConnection uses IO service to run asynchronous timers.
1085
1086 // These are the commands always supported by the DHCPv4 server.
1087 // Please keep the list in alphabetic order.
1088 CommandMgr::instance().registerCommand("build-report",
1089 std::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1090
1091 CommandMgr::instance().registerCommand("config-backend-pull",
1092 std::bind(&ControlledDhcpv4Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1093
1094 CommandMgr::instance().registerCommand("config-get",
1095 std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1096
1097 CommandMgr::instance().registerCommand("config-hash-get",
1098 std::bind(&ControlledDhcpv4Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1099
1100 CommandMgr::instance().registerCommand("config-reload",
1101 std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1102
1103 CommandMgr::instance().registerCommand("config-set",
1104 std::bind(&ControlledDhcpv4Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1105
1106 CommandMgr::instance().registerCommand("config-test",
1107 std::bind(&ControlledDhcpv4Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1108
1109 CommandMgr::instance().registerCommand("config-write",
1110 std::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1111
1112 CommandMgr::instance().registerCommand("dhcp-enable",
1113 std::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1114
1115 CommandMgr::instance().registerCommand("dhcp-disable",
1116 std::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1117
1118 CommandMgr::instance().registerCommand("leases-reclaim",
1119 std::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1120
1121 CommandMgr::instance().registerCommand("server-tag-get",
1122 std::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1123
1124 CommandMgr::instance().registerCommand("shutdown",
1125 std::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1126
1127 CommandMgr::instance().registerCommand("status-get",
1128 std::bind(&ControlledDhcpv4Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1129
1130 CommandMgr::instance().registerCommand("version-get",
1131 std::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1132
1133 // Register statistic related commands
1134 CommandMgr::instance().registerCommand("statistic-get",
1135 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1136
1137 CommandMgr::instance().registerCommand("statistic-reset",
1138 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1139
1140 CommandMgr::instance().registerCommand("statistic-remove",
1141 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1142
1143 CommandMgr::instance().registerCommand("statistic-get-all",
1144 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1145
1146 CommandMgr::instance().registerCommand("statistic-reset-all",
1147 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1148
1149 CommandMgr::instance().registerCommand("statistic-remove-all",
1150 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1151
1152 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1153 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1154
1155 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1156 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1157
1158 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1159 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1160
1161 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1162 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1163}
1164
1166 setExitValue(exit_value);
1167 getIOService()->stop(); // Stop ASIO transmissions
1168 shutdown(); // Initiate DHCPv4 shutdown procedure.
1169}
1170
1172 try {
1173 MultiThreadingMgr::instance().apply(false, 0, 0);
1176
1177 // The closure captures either a shared pointer (memory leak)
1178 // or a raw pointer (pointing to a deleted object).
1182
1183 timer_mgr_->unregisterTimers();
1184
1185 cleanup();
1186
1187 // Close the command socket (if it exists).
1188 CommandMgr::instance().closeCommandSocket();
1189
1190 // Deregister any registered commands (please keep in alphabetic order)
1191 CommandMgr::instance().deregisterCommand("build-report");
1192 CommandMgr::instance().deregisterCommand("config-backend-pull");
1193 CommandMgr::instance().deregisterCommand("config-get");
1194 CommandMgr::instance().deregisterCommand("config-hash-get");
1195 CommandMgr::instance().deregisterCommand("config-reload");
1196 CommandMgr::instance().deregisterCommand("config-set");
1197 CommandMgr::instance().deregisterCommand("config-test");
1198 CommandMgr::instance().deregisterCommand("config-write");
1199 CommandMgr::instance().deregisterCommand("dhcp-disable");
1200 CommandMgr::instance().deregisterCommand("dhcp-enable");
1201 CommandMgr::instance().deregisterCommand("leases-reclaim");
1202 CommandMgr::instance().deregisterCommand("server-tag-get");
1203 CommandMgr::instance().deregisterCommand("shutdown");
1204 CommandMgr::instance().deregisterCommand("statistic-get");
1205 CommandMgr::instance().deregisterCommand("statistic-get-all");
1206 CommandMgr::instance().deregisterCommand("statistic-remove");
1207 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1208 CommandMgr::instance().deregisterCommand("statistic-reset");
1209 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1210 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1211 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1212 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1213 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1214 CommandMgr::instance().deregisterCommand("status-get");
1215 CommandMgr::instance().deregisterCommand("version-get");
1216
1217 // Reset DatabaseConnection IO service.
1219 } catch (...) {
1220 // Don't want to throw exceptions from the destructor. The server
1221 // is shutting down anyway.
1222 }
1223
1224 server_ = NULL; // forget this instance. There should be no callback anymore
1225 // at this stage anyway.
1226}
1227
1228void
1229ControlledDhcpv4Srv::reclaimExpiredLeases(const size_t max_leases,
1230 const uint16_t timeout,
1231 const bool remove_lease,
1232 const uint16_t max_unwarned_cycles) {
1233 try {
1234 server_->alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
1235 remove_lease,
1236 max_unwarned_cycles);
1237 } catch (const std::exception& ex) {
1239 .arg(ex.what());
1240 }
1241 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1243}
1244
1245void
1246ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1247 server_->alloc_engine_->deleteExpiredReclaimedLeases4(secs);
1248 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1250}
1251
1252bool
1253ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1254 if (!db_reconnect_ctl) {
1255 // This should never happen
1257 return (false);
1258 }
1259
1260 // Disable service until the connection is recovered.
1261 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1262 db_reconnect_ctl->alterServiceState()) {
1264 }
1265
1267
1268 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1269 // return false.
1270 if (!db_reconnect_ctl->retriesLeft() ||
1271 !db_reconnect_ctl->retryInterval()) {
1273 .arg(db_reconnect_ctl->retriesLeft())
1274 .arg(db_reconnect_ctl->retryInterval());
1275 if (db_reconnect_ctl->exitOnFailure()) {
1276 shutdownServer(EXIT_FAILURE);
1277 }
1278 return (false);
1279 }
1280
1281 return (true);
1282}
1283
1284bool
1285ControlledDhcpv4Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1286 if (!db_reconnect_ctl) {
1287 // This should never happen
1289 return (false);
1290 }
1291
1292 // Enable service after the connection is recovered.
1293 if (db_reconnect_ctl->alterServiceState()) {
1295 }
1296
1298
1299 db_reconnect_ctl->resetRetries();
1300
1301 return (true);
1302}
1303
1304bool
1305ControlledDhcpv4Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1306 if (!db_reconnect_ctl) {
1307 // This should never happen
1309 return (false);
1310 }
1311
1313 .arg(db_reconnect_ctl->maxRetries());
1314
1315 if (db_reconnect_ctl->exitOnFailure()) {
1316 shutdownServer(EXIT_FAILURE);
1317 }
1318
1319 return (true);
1320}
1321
1322void
1323ControlledDhcpv4Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1324 if (!reconnect_ctl) {
1325 // This should never happen
1327 return;
1328 }
1329
1331 .arg(reconnect_ctl->maxRetries());
1332
1333 if (reconnect_ctl->exitOnFailure()) {
1334 shutdownServer(EXIT_FAILURE);
1335 }
1336}
1337
1338void
1339ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1340 boost::shared_ptr<unsigned> failure_count) {
1341 // stop thread pool (if running)
1343
1344 try {
1345 // Fetch any configuration backend updates since our last fetch.
1346 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1348 (*failure_count) = 0;
1349
1350 } catch (const std::exception& ex) {
1352 .arg(ex.what());
1353
1354 // We allow at most 10 consecutive failures after which we stop
1355 // making further attempts to fetch the configuration updates.
1356 // Let's return without re-scheduling the timer.
1357 if (++(*failure_count) > 10) {
1360 return;
1361 }
1362 }
1363
1364 // Reschedule the timer to fetch new updates or re-try if
1365 // the previous attempt resulted in an error.
1366 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1367 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1368 }
1369}
1370
1371} // namespace dhcp
1372} // namespace isc
CtrlAgentHooks Hooks
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
static std::string getHash(const isc::data::ConstElementPtr &config)
returns a hash of a given Element structure
static CommandMgr & instance()
CommandMgr is a singleton class.
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:304
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
static void setIOService(const isc::asiolink::IOServicePtr &io_service)
Sets IO service to be used by the database backends.
static DbCallback db_recovered_callback_
Optional callback function to invoke if an opened connection recovery succeeded.
static DbCallback db_failed_callback_
Optional callback function to invoke if an opened connection recovery failed.
static DbCallback db_lost_callback_
Optional callback function to invoke if an opened connection is lost.
RAII class to enable DB reconnect retries on server startup.
static const std::string FLUSH_RECLAIMED_TIMER_NAME
Name of the timer for flushing reclaimed leases.
static const std::string RECLAIM_EXPIRED_TIMER_NAME
Name of the timer for reclaiming expired leases.
static OpenSocketsFailedCallback open_sockets_failed_callback_
Optional callback function to invoke if all retries of the opening sockets fail.
Definition cfg_iface.h:361
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:25
static void apply(data::ConstElementPtr value)
apply multi threading configuration
Controlled version of the 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.
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.
DHCPv4 server service.
Definition dhcp4_srv.h:253
void shutdown() override
Instructs the server to shut down.
Definition dhcp4_srv.cc:725
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
Definition dhcp4_srv.h:304
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
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:1247
static void create()
Creates new instance of the HostMgr.
Definition host_mgr.cc:52
Handles network interfaces, transmission and reception.
Definition iface_mgr.h:656
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:54
static void destroy()
Destroy lease manager.
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition libdhcp++.cc: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.
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 boost::shared_ptr< CalloutHandle > createCalloutHandle()
Return callout handle.
static void callCallouts(int index, CalloutHandle &handle)
Calls the callouts for a given hook.
std::string getConfigFile() const
Returns config file name.
Definition daemon.cc:104
virtual size_t writeConfigFile(const std::string &config_file, isc::data::ConstElementPtr cfg=isc::data::ConstElementPtr()) const
Writes current configuration to specified file.
Definition daemon.cc:228
isc::asiolink::IOSignalSetPtr signal_set_
A pointer to the object installing custom signal handlers.
Definition daemon.h:257
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition daemon.h:263
void setExitValue(int value)
Sets the exit value.
Definition daemon.h:227
Statistics Manager class.
static StatsMgr & instance()
Statistics Manager accessor method.
RAII class creating a critical section.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
This file contains several functions and constants that are used for handling commands and responses ...
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.
static isc::data::ConstElementPtr statisticResetHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-reset command.
static isc::data::ConstElementPtr statisticGetAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-get-all command.
static isc::data::ConstElementPtr statisticRemoveHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-remove command.
static isc::data::ConstElementPtr statisticGetHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-get command.
static isc::data::ConstElementPtr statisticResetAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-reset-all command.
static isc::data::ConstElementPtr statisticSetMaxSampleAgeHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-sample-age-set command.
static isc::data::ConstElementPtr statisticRemoveAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-remove-all command.
static isc::data::ConstElementPtr statisticSetMaxSampleCountHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-sample-count-set command.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
#define LOG_FATAL(LOGGER, MESSAGE)
Macro to conveniently test fatal output and log it.
Definition macros.h:38
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
ConstElementPtr createCommand(const std::string &command)
Creates a standard command message with no argument (of the form { "command": "my_command" })
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
@ error
Definition db_log.h:118
std::string getConfigReport()
Definition cfgrpt.cc:20
const isc::log::MessageID 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.
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_DB_RECONNECT_DISABLED
const isc::log::MessageID DHCP4_CONFIG_UNRECOVERABLE_ERROR
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_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
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.