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