Kea 2.7.1
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 status->set("dhcp-state", network_state_->toElement());
803
804 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
805}
806
808ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
809 ConstElementPtr args) {
810 StatsMgr& stats_mgr = StatsMgr::instance();
811 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleCountAllHandler(args);
812 // Update the default parameter.
813 long max_samples = stats_mgr.getMaxSampleCountDefault();
814 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
815 "statistic-default-sample-count", Element::create(max_samples));
816 return (answer);
817}
818
820ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
821 ConstElementPtr args) {
822 StatsMgr& stats_mgr = StatsMgr::instance();
823 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleAgeAllHandler(args);
824 // Update the default parameter.
825 auto duration = stats_mgr.getMaxSampleAgeDefault();
826 long max_age = toSeconds(duration);
827 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
828 "statistic-default-sample-age", Element::create(max_age));
829 return (answer);
830}
831
835
836 // Allow DB reconnect on startup. The database connection parameters specify
837 // respective details.
839
840 // Single stream instance used in all error clauses
841 std::ostringstream err;
842
843 if (!srv) {
844 err << "Server object not initialized, can't process config.";
846 }
847
849 .arg(srv->redactConfig(config)->str());
850
851 ConstElementPtr answer = configureDhcp4Server(*srv, config);
852
853 // Check that configuration was successful. If not, do not reopen sockets
854 // and don't bother with DDNS stuff.
855 try {
856 int rcode = 0;
857 isc::config::parseAnswer(rcode, answer);
858 if (rcode != 0) {
859 return (answer);
860 }
861 } catch (const std::exception& ex) {
862 err << "Failed to process configuration:" << ex.what();
864 }
865
866 // Re-open lease and host database with new parameters.
867 try {
869 std::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, ph::_1);
870
872 std::bind(&ControlledDhcpv4Srv::dbRecoveredCallback, srv, ph::_1);
873
875 std::bind(&ControlledDhcpv4Srv::dbFailedCallback, srv, ph::_1);
876
877 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
878 string params = "universe=4";
879 cfg_db->setAppendedParameters(params);
880 cfg_db->createManagers();
881 // Reset counters related to connections as all managers have been recreated.
882 srv->getNetworkState()->resetForDbConnection();
883 srv->getNetworkState()->resetForLocalCommands();
884 srv->getNetworkState()->resetForRemoteCommands();
885 } catch (const std::exception& ex) {
886 err << "Unable to open database: " << ex.what();
888 }
889
890 // Server will start DDNS communications if its enabled.
891 try {
892 srv->startD2();
893 } catch (const std::exception& ex) {
894 err << "Error starting DHCP_DDNS client after server reconfiguration: "
895 << ex.what();
897 }
898
899 // Setup DHCPv4-over-DHCPv6 IPC
900 try {
901 Dhcp4to6Ipc::instance().open();
902 } catch (const std::exception& ex) {
903 err << "error starting DHCPv4-over-DHCPv6 IPC "
904 " after server reconfiguration: " << ex.what();
906 }
907
908 // Configure DHCP packet queueing
909 try {
911 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
912 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
914 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
915 }
916
917 } catch (const std::exception& ex) {
918 err << "Error setting packet queue controls after server reconfiguration: "
919 << ex.what();
921 }
922
923 // Configure a callback to shut down the server when the bind socket
924 // attempts exceeded.
926 std::bind(&ControlledDhcpv4Srv::openSocketsFailedCallback, srv, ph::_1);
927
928 // Configuration may change active interfaces. Therefore, we have to reopen
929 // sockets according to new configuration. It is possible that this
930 // operation will fail for some interfaces but the openSockets function
931 // guards against exceptions and invokes a callback function to
932 // log warnings. Since we allow that this fails for some interfaces there
933 // is no need to rollback configuration if socket fails to open on any
934 // of the interfaces.
935 CfgMgr::instance().getStagingCfg()->getCfgIface()->
936 openSockets(AF_INET, srv->getServerPort(),
938
939 // Install the timers for handling leases reclamation.
940 try {
941 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
942 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
943 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
944 server_);
945
946 } catch (const std::exception& ex) {
947 err << "unable to setup timers for periodically running the"
948 " reclamation of the expired leases: "
949 << ex.what() << ".";
951 }
952
953 // Setup config backend polling, if configured for it.
954 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
955 if (ctl_info) {
956 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
957 // Only schedule the CB fetch timer if the fetch wait time is greater
958 // than 0.
959 if (fetch_time > 0) {
960 // When we run unit tests, we want to use milliseconds unit for the
961 // specified interval. Otherwise, we use seconds. Note that using
962 // milliseconds as a unit in unit tests prevents us from waiting 1
963 // second on more before the timer goes off. Instead, we wait one
964 // millisecond which significantly reduces the test time.
965 if (!server_->inTestMode()) {
966 fetch_time = 1000 * fetch_time;
967 }
968
969 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
971 registerTimer("Dhcp4CBFetchTimer",
972 std::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
973 server_, CfgMgr::instance().getStagingCfg(),
974 failure_count),
975 fetch_time,
977 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
978 }
979 }
980
981 // Finally, we can commit runtime option definitions in libdhcp++. This is
982 // exception free.
984
985 auto notify_libraries = ControlledDhcpv4Srv::finishConfigHookLibraries(config);
986 if (notify_libraries) {
987 return (notify_libraries);
988 }
989
990
991 // Initialize the allocators. If the user selected a Free Lease Queue Allocator
992 // for any of the subnets, the server will now populate free leases to the queue.
993 // It may take a while!
994 try {
995 CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->initAllocatorsAfterConfigure();
996
997 } catch (const std::exception& ex) {
998 err << "Error initializing the lease allocators: "
999 << ex.what();
1001 }
1002
1003 // Apply multi threading settings.
1004 // @note These settings are applied/updated only if no errors occur while
1005 // applying the new configuration.
1006 // @todo This should be fixed.
1007 try {
1008 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1009 } catch (const std::exception& ex) {
1010 err << "Error applying multi threading settings: "
1011 << ex.what();
1013 }
1014
1015 return (answer);
1016}
1017
1021 // This hook point notifies hooks libraries that the configuration of the
1022 // DHCPv4 server has completed. It provides the hook library with the pointer
1023 // to the common IO service object, new server configuration in the JSON
1024 // format and with the pointer to the configuration storage where the
1025 // parsed configuration is stored.
1026 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp4_srv_configured_)) {
1028
1029 callout_handle->setArgument("io_context", srv->getIOService());
1030 callout_handle->setArgument("network_state", srv->getNetworkState());
1031 callout_handle->setArgument("json_config", config);
1032 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1033
1034 HooksManager::callCallouts(Hooks.hooks_index_dhcp4_srv_configured_,
1035 *callout_handle);
1036
1037 // If next step is DROP, report a configuration error.
1038 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1039 string error;
1040 try {
1041 callout_handle->getArgument("error", error);
1042 } catch (NoSuchArgument const& ex) {
1043 error = "unknown error";
1044 }
1046 }
1047 }
1048
1049 return (ConstElementPtr());
1050}
1051
1055
1056 if (!srv) {
1058 "Server object not initialized, can't process config.");
1059 return (no_srv);
1060 }
1061
1063 .arg(srv->redactConfig(config)->str());
1064
1065 return (configureDhcp4Server(*srv, config, true));
1066}
1067
1068ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
1069 uint16_t client_port /*= 0*/)
1070 : Dhcpv4Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1071 if (getInstance()) {
1073 "There is another Dhcpv4Srv instance already.");
1074 }
1075 server_ = this; // remember this instance for later use in handlers
1076
1077 // ProcessSpawn uses IO service to handle signal set events.
1079
1080 // TimerMgr uses IO service to run asynchronous timers.
1081 TimerMgr::instance()->setIOService(getIOService());
1082
1083 // CommandMgr uses IO service to run asynchronous socket operations.
1084 CommandMgr::instance().setIOService(getIOService());
1085
1086 // DatabaseConnection uses IO service to run asynchronous timers.
1088
1089 // These are the commands always supported by the DHCPv4 server.
1090 // Please keep the list in alphabetic order.
1091 CommandMgr::instance().registerCommand("build-report",
1092 std::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1093
1094 CommandMgr::instance().registerCommand("config-backend-pull",
1095 std::bind(&ControlledDhcpv4Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1096
1097 CommandMgr::instance().registerCommand("config-get",
1098 std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1099
1100 CommandMgr::instance().registerCommand("config-hash-get",
1101 std::bind(&ControlledDhcpv4Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1102
1103 CommandMgr::instance().registerCommand("config-reload",
1104 std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1105
1106 CommandMgr::instance().registerCommand("config-set",
1107 std::bind(&ControlledDhcpv4Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1108
1109 CommandMgr::instance().registerCommand("config-test",
1110 std::bind(&ControlledDhcpv4Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1111
1112 CommandMgr::instance().registerCommand("config-write",
1113 std::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1114
1115 CommandMgr::instance().registerCommand("dhcp-enable",
1116 std::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1117
1118 CommandMgr::instance().registerCommand("dhcp-disable",
1119 std::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1120
1121 CommandMgr::instance().registerCommand("leases-reclaim",
1122 std::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1123
1124 CommandMgr::instance().registerCommand("server-tag-get",
1125 std::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1126
1127 CommandMgr::instance().registerCommand("shutdown",
1128 std::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1129
1130 CommandMgr::instance().registerCommand("status-get",
1131 std::bind(&ControlledDhcpv4Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1132
1133 CommandMgr::instance().registerCommand("version-get",
1134 std::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1135
1136 // Register statistic related commands
1137 CommandMgr::instance().registerCommand("statistic-get",
1138 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1139
1140 CommandMgr::instance().registerCommand("statistic-reset",
1141 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1142
1143 CommandMgr::instance().registerCommand("statistic-remove",
1144 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1145
1146 CommandMgr::instance().registerCommand("statistic-get-all",
1147 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1148
1149 CommandMgr::instance().registerCommand("statistic-reset-all",
1150 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1151
1152 CommandMgr::instance().registerCommand("statistic-remove-all",
1153 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1154
1155 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1156 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1157
1158 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1159 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1160
1161 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1162 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1163
1164 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1165 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1166}
1167
1169 setExitValue(exit_value);
1170 getIOService()->stop(); // Stop ASIO transmissions
1171 shutdown(); // Initiate DHCPv4 shutdown procedure.
1172}
1173
1175 try {
1176 MultiThreadingMgr::instance().apply(false, 0, 0);
1179
1180 // The closure captures either a shared pointer (memory leak)
1181 // or a raw pointer (pointing to a deleted object).
1185
1186 timer_mgr_->unregisterTimers();
1187
1188 cleanup();
1189
1190 // Close the command socket (if it exists).
1191 CommandMgr::instance().closeCommandSocket();
1192
1193 // Deregister any registered commands (please keep in alphabetic order)
1194 CommandMgr::instance().deregisterCommand("build-report");
1195 CommandMgr::instance().deregisterCommand("config-backend-pull");
1196 CommandMgr::instance().deregisterCommand("config-get");
1197 CommandMgr::instance().deregisterCommand("config-hash-get");
1198 CommandMgr::instance().deregisterCommand("config-reload");
1199 CommandMgr::instance().deregisterCommand("config-set");
1200 CommandMgr::instance().deregisterCommand("config-test");
1201 CommandMgr::instance().deregisterCommand("config-write");
1202 CommandMgr::instance().deregisterCommand("dhcp-disable");
1203 CommandMgr::instance().deregisterCommand("dhcp-enable");
1204 CommandMgr::instance().deregisterCommand("leases-reclaim");
1205 CommandMgr::instance().deregisterCommand("server-tag-get");
1206 CommandMgr::instance().deregisterCommand("shutdown");
1207 CommandMgr::instance().deregisterCommand("statistic-get");
1208 CommandMgr::instance().deregisterCommand("statistic-get-all");
1209 CommandMgr::instance().deregisterCommand("statistic-remove");
1210 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1211 CommandMgr::instance().deregisterCommand("statistic-reset");
1212 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1213 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1214 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1215 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1216 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1217 CommandMgr::instance().deregisterCommand("status-get");
1218 CommandMgr::instance().deregisterCommand("version-get");
1219
1220 // Reset DatabaseConnection IO service.
1222 } catch (...) {
1223 // Don't want to throw exceptions from the destructor. The server
1224 // is shutting down anyway.
1225 }
1226
1227 server_ = NULL; // forget this instance. There should be no callback anymore
1228 // at this stage anyway.
1229}
1230
1231void
1232ControlledDhcpv4Srv::reclaimExpiredLeases(const size_t max_leases,
1233 const uint16_t timeout,
1234 const bool remove_lease,
1235 const uint16_t max_unwarned_cycles) {
1236 try {
1237 server_->alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
1238 remove_lease,
1239 max_unwarned_cycles);
1240 } catch (const std::exception& ex) {
1242 .arg(ex.what());
1243 }
1244 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1246}
1247
1248void
1249ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1250 server_->alloc_engine_->deleteExpiredReclaimedLeases4(secs);
1251 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1253}
1254
1255bool
1256ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1257 if (!db_reconnect_ctl) {
1258 // This should never happen
1260 return (false);
1261 }
1262
1263 // Disable service until the connection is recovered.
1264 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1265 db_reconnect_ctl->alterServiceState()) {
1267 }
1268
1270
1271 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1272 // return false.
1273 if (!db_reconnect_ctl->retriesLeft() ||
1274 !db_reconnect_ctl->retryInterval()) {
1276 .arg(db_reconnect_ctl->retriesLeft())
1277 .arg(db_reconnect_ctl->retryInterval());
1278 if (db_reconnect_ctl->exitOnFailure()) {
1279 shutdownServer(EXIT_FAILURE);
1280 }
1281 return (false);
1282 }
1283
1284 return (true);
1285}
1286
1287bool
1288ControlledDhcpv4Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1289 if (!db_reconnect_ctl) {
1290 // This should never happen
1292 return (false);
1293 }
1294
1295 // Enable service after the connection is recovered.
1296 if (db_reconnect_ctl->alterServiceState()) {
1298 }
1299
1301
1302 db_reconnect_ctl->resetRetries();
1303
1304 return (true);
1305}
1306
1307bool
1308ControlledDhcpv4Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1309 if (!db_reconnect_ctl) {
1310 // This should never happen
1312 return (false);
1313 }
1314
1316 .arg(db_reconnect_ctl->maxRetries());
1317
1318 if (db_reconnect_ctl->exitOnFailure()) {
1319 shutdownServer(EXIT_FAILURE);
1320 }
1321
1322 return (true);
1323}
1324
1325void
1326ControlledDhcpv4Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1327 if (!reconnect_ctl) {
1328 // This should never happen
1330 return;
1331 }
1332
1334 .arg(reconnect_ctl->maxRetries());
1335
1336 if (reconnect_ctl->exitOnFailure()) {
1337 shutdownServer(EXIT_FAILURE);
1338 }
1339}
1340
1341void
1342ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1343 boost::shared_ptr<unsigned> failure_count) {
1344 // stop thread pool (if running)
1346
1347 try {
1348 // Fetch any configuration backend updates since our last fetch.
1349 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1351 (*failure_count) = 0;
1352
1353 } catch (const std::exception& ex) {
1355 .arg(ex.what());
1356
1357 // We allow at most 10 consecutive failures after which we stop
1358 // making further attempts to fetch the configuration updates.
1359 // Let's return without re-scheduling the timer.
1360 if (++(*failure_count) > 10) {
1363 return;
1364 }
1365 }
1366
1367 // Reschedule the timer to fetch new updates or re-try if
1368 // the previous attempt resulted in an error.
1369 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1370 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1371 }
1372}
1373
1374} // namespace dhcp
1375} // 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:268
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: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:244
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.