Kea 3.2.0-git
ctrl_dhcp4_srv.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2026 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>
18#include <dhcp/libdhcp++.h>
20#include <dhcp4/dhcp4_log.h>
21#include <dhcp4/dhcp4to6_ipc.h>
26#include <dhcpsrv/cfgmgr.h>
27#include <dhcpsrv/db_type.h>
28#include <dhcpsrv/host_mgr.h>
32#include <hooks/hooks.h>
33#include <hooks/hooks_manager.h>
35#include <stats/stats_mgr.h>
36#include <util/encode/encode.h>
38
39#include <signal.h>
40
41#include <sstream>
42
43using namespace isc::asiolink;
44using namespace isc::config;
45using namespace isc::data;
46using namespace isc::db;
47using namespace isc::dhcp;
48using namespace isc::hooks;
49using namespace isc::stats;
50using namespace isc::util;
51using namespace std;
52namespace ph = std::placeholders;
53
54namespace {
55
57struct CtrlDhcp4Hooks {
58 int hooks_index_dhcp4_srv_configured_;
59
61 CtrlDhcp4Hooks() {
62 hooks_index_dhcp4_srv_configured_ = HooksManager::registerHook("dhcp4_srv_configured");
63 }
64
65};
66
67// Declare a Hooks object. As this is outside any function or method, it
68// will be instantiated (and the constructor run) when the module is loaded.
69// As a result, the hook indexes will be defined before any method in this
70// module is called.
71CtrlDhcp4Hooks Hooks;
72
82void signalHandler(int signo) {
83 // SIGHUP signals a request to reconfigure the server.
84 if (signo == SIGHUP) {
86 } else if ((signo == SIGTERM) || (signo == SIGINT)) {
88 }
89}
90
91}
92
93namespace isc {
94namespace dhcp {
95
96ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = 0;
97
98void
99ControlledDhcpv4Srv::init(const std::string& file_name) {
100 // Keep the call timestamp.
101 start_ = boost::posix_time::second_clock::universal_time();
102
103 // Configure the server using JSON file.
104 ConstElementPtr result = loadConfigFile(file_name);
105
106 int rcode;
107 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
108 if (rcode != CONTROL_RESULT_SUCCESS) {
109 string reason = comment ? comment->stringValue() :
110 "no details available";
111 isc_throw(isc::BadValue, reason);
112 }
113
114 // Set signal handlers. When the SIGHUP is received by the process
115 // the server reconfiguration will be triggered. When SIGTERM or
116 // SIGINT will be received, the server will start shutting down.
117 signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
118
119 signal_set_->add(SIGINT);
120 signal_set_->add(SIGHUP);
121 signal_set_->add(SIGTERM);
122}
123
125 signal_set_.reset();
126 getIOService()->stopAndPoll();
127}
128
130ControlledDhcpv4Srv::loadConfigFile(const std::string& file_name) {
131 // This is a configuration backend implementation that reads the
132 // configuration from a JSON file.
133
136
137 // Basic sanity check: file name must not be empty.
138 try {
139 if (file_name.empty()) {
140 // Basic sanity check: file name must not be empty.
141 isc_throw(isc::BadValue, "JSON configuration file not specified."
142 " Please use -c command line option.");
143 }
144
145 // Read contents of the file and parse it as JSON
146 Parser4Context parser;
147 json = parser.parseFile(file_name, Parser4Context::PARSER_DHCP4);
148 if (!json) {
149 isc_throw(isc::BadValue, "no configuration found");
150 }
151
152 // Let's do sanity check before we call json->get() which
153 // works only for map.
154 if (json->getType() != isc::data::Element::map) {
155 isc_throw(isc::BadValue, "Configuration file is expected to be "
156 "a map, i.e., start with { and end with } and contain "
157 "at least an entry called 'Dhcp4' that itself is a map. "
158 << file_name
159 << " is a valid JSON, but its top element is not a map."
160 " Did you forget to add { } around your configuration?");
161 }
162
163 // Use parsed JSON structures to configure the server
164 result = CommandMgr::instance().processCommand(createCommand("config-set", json));
165 if (!result) {
166 // Undetermined status of the configuration. This should never
167 // happen, but as the configureDhcp4Server returns a pointer, it is
168 // theoretically possible that it will return NULL.
169 isc_throw(isc::BadValue, "undefined result of "
170 "process command \"config-set\"");
171 }
172
173 // Now check is the returned result is successful (rcode=0) or not
174 // (see @ref isc::config::parseAnswer).
175 int rcode;
176 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
177 if (rcode != CONTROL_RESULT_SUCCESS) {
178 string reason = comment ? comment->stringValue() :
179 "no details available";
180 isc_throw(isc::BadValue, reason);
181 }
182 } catch (const std::exception& ex) {
183 // If configuration failed at any stage, we drop the staging
184 // configuration and continue to use the previous one.
186
188 .arg(file_name).arg(ex.what());
189 isc_throw(isc::BadValue, "configuration error using file '"
190 << file_name << "': " << ex.what());
191 }
192
194 .arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
195 .arg(MultiThreadingMgr::instance().getThreadPoolSize())
196 .arg(MultiThreadingMgr::instance().getPacketQueueSize());
197
198 return (result);
199}
200
201bool
205
210 return (createAnswer(CONTROL_RESULT_ERROR, "Shutdown failure."));
211 }
212
213 int exit_value = 0;
214 if (args) {
215 // @todo Should we go ahead and shutdown even if the args are invalid?
216 if (args->getType() != Element::map) {
217 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
218 }
219
220 ConstElementPtr param = args->get("exit-value");
221 if (param) {
222 if (param->getType() != Element::integer) {
224 "parameter 'exit-value' is not an integer"));
225 }
226
227 exit_value = param->intValue();
228 }
229 }
230
232 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
233}
234
237 ConstElementPtr /*args*/) {
238 if (!IfaceMgr::instance().isMainThread()) {
240 "Illegal operation executing 'config-reload' on a different thread than main thread"));
241 }
242 // Get configuration file name.
244 try {
246 auto result = loadConfigFile(file);
248 return (result);
249 } catch (const std::exception& ex) {
250 // Log the unsuccessful reconfiguration. The reason for failure
251 // should be already logged. Don't rethrow an exception so as
252 // the server keeps working.
254 .arg(file);
256 "Config reload failed: " + string(ex.what())));
257 }
258}
259
262 ConstElementPtr /*args*/) {
264 string hash = BaseCommandMgr::getHash(config);
265 config->set("hash", Element::create(hash));
266
268}
269
272 ConstElementPtr /*args*/) {
274
275 string hash = BaseCommandMgr::getHash(config);
276
278 params->set("hash", Element::create(hash));
279 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
280}
281
284 ConstElementPtr args) {
285 string filename;
286
287 if (args) {
288 if (args->getType() != Element::map) {
289 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
290 }
291 ConstElementPtr filename_param = args->get("filename");
292 if (filename_param) {
293 if (filename_param->getType() != Element::string) {
295 "passed parameter 'filename' is not a string"));
296 }
297 filename = filename_param->stringValue();
298 }
299 }
300
301 if (filename.empty()) {
302 // filename parameter was not specified, so let's use whatever we remember
303 // from the command-line
304 filename = getConfigFile();
305 if (filename.empty()) {
306 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
307 "Please specify filename explicitly."));
308 }
309 } else {
310 try {
311 checkWriteConfigFile(filename);
312 } catch (const isc::Exception& ex) {
313 std::ostringstream msg;
314 msg << "not allowed to write config into " << filename
315 << ": " << ex.what();
316 return (createAnswer(CONTROL_RESULT_ERROR, msg.str()));
317 }
318 }
319
320 // Ok, it's time to write the file.
321 size_t size = 0;
322 try {
323 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
324 size = writeConfigFile(filename, cfg);
325 } catch (const isc::Exception& ex) {
326 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during config-write: ")
327 + ex.what()));
328 }
329 if (size == 0) {
330 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
331 + filename));
332 }
333
334 // Ok, it's time to return the successful response.
336 params->set("size", Element::create(static_cast<long long>(size)));
337 params->set("filename", Element::create(filename));
338
339 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
340 + filename + " successful", params));
341}
342
345 ConstElementPtr args) {
346 if (!IfaceMgr::instance().isMainThread()) {
348 "Illegal operation executing 'config-set' on a different thread than main thread"));
349 }
350 const int status_code = CONTROL_RESULT_ERROR;
351 ConstElementPtr dhcp4;
352 string message;
353
354 // Command arguments are expected to be:
355 // { "Dhcp4": { ... } }
356 if (!args) {
357 message = "Missing mandatory 'arguments' parameter.";
358 } else {
359 dhcp4 = args->get("Dhcp4");
360 if (!dhcp4) {
361 message = "Missing mandatory 'Dhcp4' parameter.";
362 } else if (dhcp4->getType() != Element::map) {
363 message = "'Dhcp4' parameter expected to be a map.";
364 }
365 }
366
367 // Check unsupported objects.
368 if (message.empty()) {
369 for (auto const& obj : args->mapValue()) {
370 const string& obj_name = obj.first;
371 if (obj_name != "Dhcp4") {
373 .arg(obj_name);
374 if (message.empty()) {
375 message = "Unsupported '" + obj_name + "' parameter";
376 } else {
377 message += " (and '" + obj_name + "')";
378 }
379 }
380 }
381 if (!message.empty()) {
382 message += ".";
383 }
384 }
385
386 if (!message.empty()) {
387 // Something is amiss with arguments, return a failure response.
388 ConstElementPtr result = isc::config::createAnswer(status_code,
389 message);
390 return (result);
391 }
392
394 (LeaseMgrFactory::instance().getType() == "memfile")) {
396 auto file_name = mgr.getLeaseFilePath(Memfile_LeaseMgr::V4);
399 "Can not update configuration while lease file cleanup process is running."));
400 }
401 }
402
403 // stop thread pool (if running)
405
406 // We are starting the configuration process so we should remove any
407 // staging configuration that has been created during previous
408 // configuration attempts.
410
411 // Parse the logger configuration explicitly into the staging config.
412 // Note this does not alter the current loggers, they remain in
413 // effect until we apply the logging config below. If no logging
414 // is supplied logging will revert to default logging.
415 Daemon::configureLogger(dhcp4, CfgMgr::instance().getStagingCfg());
416
417 // Let's apply the new logging. We do it early, so we'll be able to print
418 // out what exactly is wrong with the new config in case of problems.
419 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
420
421 // Now we configure the server proper.
422 ConstElementPtr result = processConfig(dhcp4);
423
424 // If the configuration parsed successfully, apply the new logger
425 // configuration and then commit the new configuration. We apply
426 // the logging first in case there's a configuration failure.
427 int rcode = 0;
428 isc::config::parseAnswer(rcode, result);
429 if (getShutdown() && (rcode == CONTROL_RESULT_SUCCESS)) {
430 // Do not return success when a fatal error was triggered.
432 message = "Reconfiguration triggered a fatal error: shutting down.";
433 result = isc::config::createAnswer(rcode, message);
434 }
435 if (rcode == CONTROL_RESULT_SUCCESS) {
436 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
437
438 // Use new configuration.
440 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
441 // Ok, we applied the logging from the upcoming configuration, but
442 // there were problems with the config. As such, we need to back off
443 // and revert to the previous logging configuration. This is not done if
444 // sequence == 0, because that would mean always reverting to stdout by
445 // default, and it is arguably more helpful to have the error in a
446 // potential file or syslog configured in the upcoming configuration.
447 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
448
449 if (rcode == CONTROL_RESULT_FATAL_ERROR) {
450 // Not initial configuration so someone can believe we reverted
451 // to the previous configuration. It is not the case so be clear
452 // about this.
454 }
455 }
456
458 try {
459 // Handle events registered by hooks using external IOService objects.
461 } catch (const std::exception& ex) {
462 if (rcode == CONTROL_RESULT_FATAL_ERROR) {
463 return (result);
464 }
465 std::ostringstream err;
466 err << "Error initializing hooks: "
467 << ex.what();
469 }
470
471 return (result);
472}
473
476 ConstElementPtr args) {
477 if (!IfaceMgr::instance().isMainThread()) {
479 "Illegal operation executing 'config-test' on a different thread than main thread"));
480 }
481 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
482 ConstElementPtr dhcp4;
483 string message;
484
485 // Command arguments are expected to be:
486 // { "Dhcp4": { ... } }
487 if (!args) {
488 message = "Missing mandatory 'arguments' parameter.";
489 } else {
490 dhcp4 = args->get("Dhcp4");
491 if (!dhcp4) {
492 message = "Missing mandatory 'Dhcp4' parameter.";
493 } else if (dhcp4->getType() != Element::map) {
494 message = "'Dhcp4' parameter expected to be a map.";
495 }
496 }
497
498 // Check unsupported objects.
499 if (message.empty()) {
500 for (auto const& obj : args->mapValue()) {
501 const string& obj_name = obj.first;
502 if (obj_name != "Dhcp4") {
504 .arg(obj_name);
505 if (message.empty()) {
506 message = "Unsupported '" + obj_name + "' parameter";
507 } else {
508 message += " (and '" + obj_name + "')";
509 }
510 }
511 }
512 if (!message.empty()) {
513 message += ".";
514 }
515 }
516
517 if (!message.empty()) {
518 // Something is amiss with arguments, return a failure response.
519 ConstElementPtr result = isc::config::createAnswer(status_code,
520 message);
521 return (result);
522 }
523
524 // stop thread pool (if running)
526
527 // We are starting the configuration process so we should remove any
528 // staging configuration that has been created during previous
529 // configuration attempts.
531
532 // Now we check the server proper.
533 return (checkConfig(dhcp4));
534}
535
538 ConstElementPtr args) {
539 std::ostringstream message;
540 int64_t max_period = 0;
541 std::string origin;
542
543 // If the args map does not contain 'origin' parameter, the default type
544 // will be used (user command).
545 auto type = NetworkState::USER_COMMAND;
546
547 // Parse arguments to see if the 'max-period' or 'origin' parameters have
548 // been specified.
549 if (args) {
550 // Arguments must be a map.
551 if (args->getType() != Element::map) {
552 message << "arguments for the 'dhcp-disable' command must be a map";
553
554 } else {
555 ConstElementPtr max_period_element = args->get("max-period");
556 // max-period is optional.
557 if (max_period_element) {
558 // It must be an integer, if specified.
559 if (max_period_element->getType() != Element::integer) {
560 message << "'max-period' argument must be a number";
561
562 } else {
563 // It must be positive integer.
564 max_period = max_period_element->intValue();
565 if (max_period <= 0) {
566 message << "'max-period' must be positive integer";
567 }
568 }
569 }
570 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
571 // stable release. However, the 'origin' is kept for backward compatibility
572 // with Kea versions before 2.5.8. It is common to receive both parameters
573 // because HA hook library sends both in case the partner server hasn't been
574 // upgraded to the new version. The 'origin-id' takes precedence over the
575 // 'origin'.
576 ConstElementPtr origin_id_element = args->get("origin-id");
577 ConstElementPtr origin_element = args->get("origin");
578 // The 'origin-id' and 'origin' arguments are optional.
579 if (origin_id_element) {
580 if (origin_id_element->getType() == Element::integer) {
581 type = origin_id_element->intValue();
582 } else {
583 message << "'origin-id' argument must be a number";
584 }
585 } else if (origin_element) {
586 switch (origin_element->getType()) {
587 case Element::string:
588 origin = origin_element->stringValue();
589 if (origin == "ha-partner") {
591 } else if (origin != "user") {
592 if (origin.empty()) {
593 origin = "(empty string)";
594 }
595 message << "invalid value used for 'origin' parameter: "
596 << origin;
597 }
598 break;
599 case Element::integer:
600 type = origin_element->intValue();
601 break;
602 default:
603 // It must be a string or a number, if specified.
604 message << "'origin' argument must be a string or a number";
605 }
606 }
607 }
608 }
609
610 // No error occurred, so let's disable the service.
611 if (message.tellp() == 0) {
612 message << "DHCPv4 service disabled";
613 if (max_period > 0) {
614 message << " for " << max_period << " seconds";
615
616 // The user specified that the DHCP service should resume not
617 // later than in max-period seconds. If the 'dhcp-enable' command
618 // is not sent, the DHCP service will resume automatically.
619 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
620 type);
621 }
622 network_state_->disableService(type);
623
624 // Success.
625 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
626 }
627
628 // Failure.
629 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
630}
631
634 ConstElementPtr args) {
635 std::ostringstream message;
636 std::string origin;
637
638 // If the args map does not contain 'origin' parameter, the default type
639 // will be used (user command).
640 auto type = NetworkState::USER_COMMAND;
641
642 // Parse arguments to see if the 'origin' parameter has been specified.
643 if (args) {
644 // Arguments must be a map.
645 if (args->getType() != Element::map) {
646 message << "arguments for the 'dhcp-enable' command must be a map";
647
648 } else {
649 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
650 // stable release. However, the 'origin' is kept for backward compatibility
651 // with Kea versions before 2.5.8. It is common to receive both parameters
652 // because HA hook library sends both in case the partner server hasn't been
653 // upgraded to the new version. The 'origin-id' takes precedence over the
654 // 'origin'.
655 ConstElementPtr origin_id_element = args->get("origin-id");
656 ConstElementPtr origin_element = args->get("origin");
657 // The 'origin-id' and 'origin' arguments are optional.
658 if (origin_id_element) {
659 if (origin_id_element->getType() == Element::integer) {
660 type = origin_id_element->intValue();
661 } else {
662 message << "'origin-id' argument must be a number";
663 }
664 } else if (origin_element) {
665 switch (origin_element->getType()) {
666 case Element::string:
667 origin = origin_element->stringValue();
668 if (origin == "ha-partner") {
670 } else if (origin != "user") {
671 if (origin.empty()) {
672 origin = "(empty string)";
673 }
674 message << "invalid value used for 'origin' parameter: "
675 << origin;
676 }
677 break;
678 case Element::integer:
679 type = origin_element->intValue();
680 break;
681 default:
682 // It must be a string or a number, if specified.
683 message << "'origin' argument must be a string or a number";
684 }
685 }
686 }
687 }
688
689 // No error occurred, so let's enable the service.
690 if (message.tellp() == 0) {
691 network_state_->enableService(type);
692
693 // Success.
695 "DHCP service successfully enabled"));
696 }
697
698 // Failure.
699 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
700}
701
706 std::string message;
707 bool error = false;
708 try {
709 ifaces->set("interfaces", IfaceMgr::instance().ifacesToElement());
710 } catch (const std::exception& ex) {
711 error = true;
712 message = ex.what();
713 } catch (...) {
714 error = true;
715 message = "unknown error";
716 }
717
718 ostringstream msg;
719 if (!error) {
721 << " interfaces detected.";
722 return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, msg.str(), ifaces));
723 } else {
724 msg << "Unexpected error while retrieving the list of detected interfaces: " << message;
726 }
727}
728
731 ConstElementPtr args) {
732 if (!IfaceMgr::instance().isMainThread()) {
734 "Illegal operation executing 'interface-redetect' on a different thread than main thread"));
735 }
736 std::string message;
737 bool error = false;
738 try {
739 // stop thread pool (if running)
743 } catch (const std::exception& ex) {
744 error = true;
745 message = ex.what();
746 } catch (...) {
747 error = true;
748 message = "unknown error";
749 }
750
751 ostringstream msg;
752 if (!error) {
754 } else {
755 msg << "Unexpected error while retrieving the list of detected interfaces: " << message;
757 }
758}
759
762 ConstElementPtr args) {
763 if (!IfaceMgr::instance().isMainThread()) {
765 "Illegal operation executing 'interface-add' on a different thread than main thread"));
766 }
767 string message;
768 ConstElementPtr ifaces_config;
769 if (!args) {
770 message = "Missing mandatory 'arguments' parameter.";
771 } else {
772 if (args->getType() != Element::map) {
773 message = "arguments for the 'interface-add' command must be a map";
774 } else {
775 ifaces_config = args->get("interfaces");
776 if (!ifaces_config) {
777 message = "Missing mandatory 'interfaces' map parameter in 'arguments'.";
778 }
779 auto map = args->mapValue();
780 for (auto const& key : map) {
781 if (key.first != "interfaces") {
782 message = "Unsupported '" + key.first + "' map parameter in 'arguments'.";
783 break;
784 }
785 }
786 }
787 }
788
789 if (!message.empty()) {
791 }
792 if (!ifaces_config->size()) {
793 return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Interface configuration successfully updated."));
794 }
795 bool error = false;
796 try {
797 CfgIfacePtr running_cfg = CfgMgr::instance().getCurrentCfg()->getCfgIface();
799 std::set<std::string> seen;
800 auto running_ifaces = running_cfg->toElement()->get("interfaces");
801 if (running_ifaces && (running_ifaces->getType() == Element::list)) {
802 for (auto const& item : running_ifaces->listValue()) {
803 seen.insert(item->stringValue());
804 ifaces->add(item);
805 }
806 }
807 for (auto const& item : ifaces_config->listValue()) {
808 auto const& str = item->stringValue();
809 if (seen.find(item->stringValue()) != seen.end()) {
810 continue;
811 }
812 seen.insert(item->stringValue());
813 ifaces->add(item);
814 }
815 IfacesConfigParser parser(AF_INET, true);
816 CfgIfacePtr cfg_iface(new CfgIface());
817 parser.parseInterfacesList(cfg_iface, ifaces);
818 running_cfg->update(*cfg_iface);
819 running_cfg->triggerOpenSocketsWithRetry(AF_INET, getServerPort(), useBroadcast());
820 } catch (const std::exception& ex) {
821 error = true;
822 message = ex.what();
823 } catch (...) {
824 error = true;
825 message = "unknown error";
826 }
827
828 ostringstream msg;
829 if (!error) {
830 if (getShutdown()) {
831 return (isc::config::createAnswer(CONTROL_RESULT_FATAL_ERROR, "Interface configuration update triggered a fatal error: shutting down."));
832 }
833 return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Interface configuration successfully updated."));
834 } else {
835 msg << "Updating used interfaces failed: " << message;
837 }
838}
839
843 ElementPtr arguments = Element::createMap();
844 arguments->set("extended", extended);
847 arguments);
848 return (answer);
849}
850
858
861 ConstElementPtr args) {
862 int status_code = CONTROL_RESULT_ERROR;
863 string message;
864
865 // args must be { "remove": <bool> }
866 if (!args) {
867 message = "Missing mandatory 'remove' parameter.";
868 } else {
869 ConstElementPtr remove_name = args->get("remove");
870 if (!remove_name) {
871 message = "Missing mandatory 'remove' parameter.";
872 } else if (remove_name->getType() != Element::boolean) {
873 message = "'remove' parameter expected to be a boolean.";
874 } else {
875 bool remove_lease = remove_name->boolValue();
876 server_->alloc_engine_->reclaimExpiredLeases4(0, 0, remove_lease);
877 status_code = 0;
878 message = "Reclamation of expired leases is complete.";
879 }
880 }
881 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
882 return (answer);
883}
884
887 ConstElementPtr args) {
888 if (!args) {
889 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
890 }
891 if (args->getType() != Element::map) {
892 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
893 }
894 bool ignore_link_sel =
895 CfgMgr::instance().getCurrentCfg()->getIgnoreRAILinkSelection();
896 SubnetSelector selector;
897 for (auto const& entry : args->mapValue()) {
898 ostringstream errmsg;
899 if (entry.first == "interface") {
900 if (entry.second->getType() != Element::string) {
901 errmsg << "'interface' entry must be a string";
902 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
903 }
904 selector.iface_name_ = entry.second->stringValue();
905 continue;
906 } else if (entry.first == "address") {
907 if (entry.second->getType() != Element::string) {
908 errmsg << "'address' entry must be a string";
909 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
910 }
911 try {
912 IOAddress addr(entry.second->stringValue());
913 if (!addr.isV4()) {
914 errmsg << "bad 'address' entry: not IPv4";
915 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
916 }
917 selector.ciaddr_ = addr;
918 continue;
919 } catch (const exception& ex) {
920 errmsg << "bad 'address' entry: " << ex.what();
921 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
922 }
923 } else if (entry.first == "relay") {
924 if (entry.second->getType() != Element::string) {
925 errmsg << "'relay' entry must be a string";
926 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
927 }
928 try {
929 IOAddress addr(entry.second->stringValue());
930 if (!addr.isV4()) {
931 errmsg << "bad 'relay' entry: not IPv4";
932 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
933 }
934 selector.giaddr_ = addr;
935 continue;
936 } catch (const exception& ex) {
937 errmsg << "bad 'relay' entry: " << ex.what();
938 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
939 }
940 } else if (entry.first == "local") {
941 if (entry.second->getType() != Element::string) {
942 errmsg << "'local' entry must be a string";
943 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
944 }
945 try {
946 IOAddress addr(entry.second->stringValue());
947 if (!addr.isV4()) {
948 errmsg << "bad 'local' entry: not IPv4";
949 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
950 }
951 selector.local_address_ = addr;
952 continue;
953 } catch (const exception& ex) {
954 errmsg << "bad 'local' entry: " << ex.what();
955 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
956 }
957 } else if (entry.first == "remote") {
958 if (entry.second->getType() != Element::string) {
959 errmsg << "'remote' entry must be a string";
960 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
961 }
962 try {
963 IOAddress addr(entry.second->stringValue());
964 if (!addr.isV4()) {
965 errmsg << "bad 'remote' entry: not IPv4";
966 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
967 }
968 selector.remote_address_ = addr;
969 continue;
970 } catch (const exception& ex) {
971 errmsg << "bad 'remote' entry: " << ex.what();
972 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
973 }
974 } else if (entry.first == "link") {
975 if (entry.second->getType() != Element::string) {
976 errmsg << "'link' entry must be a string";
977 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
978 }
979 try {
980 IOAddress addr(entry.second->stringValue());
981 if (!addr.isV4()) {
982 errmsg << "bad 'link' entry: not IPv4";
983 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
984 }
985 if (!ignore_link_sel) {
986 selector.option_select_ = addr;
987 }
988 continue;
989 } catch (const exception& ex) {
990 errmsg << "bad 'link' entry: " << ex.what();
991 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
992 }
993 } else if (entry.first == "subnet") {
994 // RAI link-selection has precedence over subnet-selection.
995 if (args->contains("link") && !ignore_link_sel) {
996 continue;
997 }
998 if (entry.second->getType() != Element::string) {
999 errmsg << "'subnet' entry must be a string";
1000 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1001 }
1002 try {
1003 IOAddress addr(entry.second->stringValue());
1004 if (!addr.isV4()) {
1005 errmsg << "bad 'subnet' entry: not IPv4";
1006 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1007 }
1008 selector.option_select_ = addr;
1009 continue;
1010 } catch (const exception& ex) {
1011 errmsg << "bad 'subnet' entry: " << ex.what();
1012 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1013 }
1014 } else if (entry.first == "classes") {
1015 if (entry.second->getType() != Element::list) {
1017 "'classes' entry must be a list"));
1018 }
1019 for (auto const& item : entry.second->listValue()) {
1020 if (!item || (item->getType() != Element::string)) {
1021 errmsg << "'classes' entry must be a list of strings";
1022 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1023 }
1024 // Skip empty client classes.
1025 if (!item->stringValue().empty()) {
1026 selector.client_classes_.insert(item->stringValue());
1027 }
1028 }
1029 continue;
1030 } else {
1031 errmsg << "unknown entry '" << entry.first << "'";
1032 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1033 }
1034 }
1036 getCfgSubnets4()->selectSubnet(selector);
1037 if (!subnet) {
1038 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
1039 }
1040 SharedNetwork4Ptr network;
1041 subnet->getSharedNetwork(network);
1042 ostringstream msg;
1043 if (network) {
1044 msg << "selected shared network '" << network->getName()
1045 << "' starting with subnet '" << subnet->toText()
1046 << "' id " << subnet->getID();
1047 } else {
1048 msg << "selected subnet '" << subnet->toText()
1049 << "' id " << subnet->getID();
1050 }
1051 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
1052}
1053
1056 ConstElementPtr args) {
1057 if (!args) {
1058 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
1059 }
1060 if (args->getType() != Element::map) {
1061 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
1062 }
1063 SubnetSelector selector;
1064 selector.dhcp4o6_ = true;
1067 for (auto const& entry : args->mapValue()) {
1068 ostringstream errmsg;
1069 if (entry.first == "interface") {
1070 if (entry.second->getType() != Element::string) {
1071 errmsg << "'interface' entry must be a string";
1072 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1073 }
1074 selector.iface_name_ = entry.second->stringValue();
1075 continue;
1076 } if (entry.first == "interface-id") {
1077 if (entry.second->getType() != Element::string) {
1078 errmsg << "'interface-id' entry must be a string";
1079 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1080 }
1081 try {
1082 string str = entry.second->stringValue();
1083 vector<uint8_t> id = util::str::quotedStringToBinary(str);
1084 if (id.empty()) {
1086 }
1087 if (id.empty()) {
1088 errmsg << "'interface-id' must be not empty";
1089 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1090 }
1093 id));
1094 continue;
1095 } catch (...) {
1096 errmsg << "value of 'interface-id' was not recognized";
1097 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1098 }
1099 } else if (entry.first == "address") {
1100 if (entry.second->getType() != Element::string) {
1101 errmsg << "'address' entry must be a string";
1102 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1103 }
1104 try {
1105 IOAddress addr(entry.second->stringValue());
1106 if (!addr.isV4()) {
1107 errmsg << "bad 'address' entry: not IPv4";
1108 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1109 }
1110 selector.ciaddr_ = addr;
1111 continue;
1112 } catch (const exception& ex) {
1113 errmsg << "bad 'address' entry: " << ex.what();
1114 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1115 }
1116 } else if (entry.first == "relay") {
1117 if (entry.second->getType() != Element::string) {
1118 errmsg << "'relay' entry must be a string";
1119 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1120 }
1121 try {
1122 IOAddress addr(entry.second->stringValue());
1123 if (!addr.isV4()) {
1124 errmsg << "bad 'relay' entry: not IPv4";
1125 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1126 }
1127 selector.giaddr_ = addr;
1128 continue;
1129 } catch (const exception& ex) {
1130 errmsg << "bad 'relay' entry: " << ex.what();
1131 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1132 }
1133 } else if (entry.first == "local") {
1134 if (entry.second->getType() != Element::string) {
1135 errmsg << "'local' entry must be a string";
1136 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1137 }
1138 try {
1139 IOAddress addr(entry.second->stringValue());
1140 if (!addr.isV6()) {
1141 errmsg << "bad 'local' entry: not IPv6";
1142 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1143 }
1144 selector.local_address_ = addr;
1145 continue;
1146 } catch (const exception& ex) {
1147 errmsg << "bad 'local' entry: " << ex.what();
1148 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1149 }
1150 } else if (entry.first == "remote") {
1151 if (entry.second->getType() != Element::string) {
1152 errmsg << "'remote' entry must be a string";
1153 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1154 }
1155 try {
1156 IOAddress addr(entry.second->stringValue());
1157 if (!addr.isV6()) {
1158 errmsg << "bad 'remote' entry: not IPv6";
1159 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1160 }
1161 selector.remote_address_ = addr;
1162 continue;
1163 } catch (const exception& ex) {
1164 errmsg << "bad 'remote' entry: " << ex.what();
1165 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1166 }
1167 } else if (entry.first == "link") {
1168 if (entry.second->getType() != Element::string) {
1169 errmsg << "'link' entry must be a string";
1170 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1171 }
1172 try {
1173 IOAddress addr(entry.second->stringValue());
1174 if (!addr.isV6()) {
1175 errmsg << "bad 'link' entry: not IPv6";
1176 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1177 }
1178 selector.first_relay_linkaddr_ = addr;
1179 continue;
1180 } catch (const exception& ex) {
1181 errmsg << "bad 'link' entry: " << ex.what();
1182 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1183 }
1184 } else if (entry.first == "subnet") {
1185 if (entry.second->getType() != Element::string) {
1186 errmsg << "'subnet' entry must be a string";
1187 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1188 }
1189 try {
1190 IOAddress addr(entry.second->stringValue());
1191 if (!addr.isV4()) {
1192 errmsg << "bad 'subnet' entry: not IPv4";
1193 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1194 }
1195 selector.option_select_ = addr;
1196 continue;
1197 } catch (const exception& ex) {
1198 errmsg << "bad 'subnet' entry: " << ex.what();
1199 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1200 }
1201 } else if (entry.first == "classes") {
1202 if (entry.second->getType() != Element::list) {
1204 "'classes' entry must be a list"));
1205 }
1206 for (auto const& item : entry.second->listValue()) {
1207 if (!item || (item->getType() != Element::string)) {
1208 errmsg << "'classes' entry must be a list of strings";
1209 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1210 }
1211 // Skip empty client classes.
1212 if (!item->stringValue().empty()) {
1213 selector.client_classes_.insert(item->stringValue());
1214 }
1215 }
1216 continue;
1217 } else {
1218 errmsg << "unknown entry '" << entry.first << "'";
1219 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1220 }
1221 }
1223 getCfgSubnets4()->selectSubnet4o6(selector);
1224 if (!subnet) {
1225 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
1226 }
1227 SharedNetwork4Ptr network;
1228 subnet->getSharedNetwork(network);
1229 ostringstream msg;
1230 if (network) {
1231 msg << "selected shared network '" << network->getName()
1232 << "' starting with subnet '" << subnet->toText()
1233 << "' id " << subnet->getID();
1234 } else {
1235 msg << "selected subnet '" << subnet->toText()
1236 << "' id " << subnet->getID();
1237 }
1238 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
1239}
1240
1244 const std::string& tag =
1245 CfgMgr::instance().getCurrentCfg()->getServerTag();
1246 ElementPtr response = Element::createMap();
1247 response->set("server-tag", Element::create(tag));
1248
1249 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
1250}
1251
1255 if (!IfaceMgr::instance().isMainThread()) {
1257 "Illegal operation executing 'config-backend-pull' on a different thread than main thread"));
1258 }
1259 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
1260 if (!ctl_info) {
1261 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
1262 }
1263
1264 // stop thread pool (if running)
1266
1267 // Reschedule the periodic CB fetch.
1268 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1269 TimerMgr::instance()->cancel("Dhcp4CBFetchTimer");
1270 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1271 }
1272
1273 // Code from cbFetchUpdates.
1274 // The configuration to use is the current one because this is called
1275 // after the configuration manager commit.
1276 try {
1277 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
1278 auto mode = CBControlDHCPv4::FetchMode::FETCH_UPDATE;
1279 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
1280 } catch (const std::exception& ex) {
1282 .arg(ex.what());
1284 "On demand configuration update failed: " +
1285 string(ex.what())));
1286 }
1288 "On demand configuration update successful."));
1289}
1290
1293 ConstElementPtr /*args*/) {
1294 ElementPtr status = Element::createMap();
1295 status->set("pid", Element::create(static_cast<int>(getpid())));
1296
1297 auto now = boost::posix_time::second_clock::universal_time();
1298 // Sanity check: start_ is always initialized.
1299 if (!start_.is_not_a_date_time()) {
1300 auto uptime = now - start_;
1301 status->set("uptime", Element::create(uptime.total_seconds()));
1302 }
1303
1304 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
1305 if (!last_commit.is_not_a_date_time()) {
1306 auto reload = now - last_commit;
1307 status->set("reload", Element::create(reload.total_seconds()));
1308 }
1309
1310 auto& mt_mgr = MultiThreadingMgr::instance();
1311 if (mt_mgr.getMode()) {
1312 status->set("multi-threading-enabled", Element::create(true));
1313 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
1314 MultiThreadingMgr::instance().getThreadPoolSize())));
1315 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
1316 MultiThreadingMgr::instance().getPacketQueueSize())));
1317 ElementPtr queue_stats = Element::createList();
1318 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
1319 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
1320 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
1321 status->set("packet-queue-statistics", queue_stats);
1322
1323 } else {
1324 status->set("multi-threading-enabled", Element::create(false));
1325 }
1326
1327 // Merge lease manager status.
1328 ElementPtr lm_info;
1331 }
1332 if (lm_info && (lm_info->getType() == Element::map)) {
1333 for (auto const& entry : lm_info->mapValue()) {
1334 status->set(entry.first, entry.second);
1335 }
1336 }
1337
1338 // Iterate through the interfaces and get all the errors.
1339 ElementPtr socket_errors(Element::createList());
1340 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
1341 for (std::string const& error : interface->getErrors()) {
1342 socket_errors->add(Element::create(error));
1343 }
1344 }
1345
1346 // Abstract the information from all sockets into a single status.
1347 ElementPtr sockets(Element::createMap());
1348 if (socket_errors->empty()) {
1349 sockets->set("status", Element::create("ready"));
1350 } else {
1351 ReconnectCtlPtr const reconnect_ctl(
1352 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
1353 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
1354 sockets->set("status", Element::create("retrying"));
1355 } else {
1356 sockets->set("status", Element::create("failed"));
1357 }
1358 sockets->set("errors", socket_errors);
1359 }
1360 status->set("sockets", sockets);
1361
1362 status->set("dhcp-state", network_state_->toElement());
1363
1364 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
1365}
1366
1369 ConstElementPtr args) {
1370 StatsMgr& stats_mgr = StatsMgr::instance();
1372 // Update the default parameter.
1373 long max_samples = stats_mgr.getMaxSampleCountDefault();
1374 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1375 "statistic-default-sample-count", Element::create(max_samples));
1376 return (answer);
1377}
1378
1381 ConstElementPtr args) {
1382 StatsMgr& stats_mgr = StatsMgr::instance();
1383 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleAgeAllHandler(args);
1384 // Update the default parameter.
1385 auto duration = stats_mgr.getMaxSampleAgeDefault();
1386 long max_age = toSeconds(duration);
1387 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1388 "statistic-default-sample-age", Element::create(max_age));
1389 return (answer);
1390}
1391
1395 return (LeaseMgrFactory::instance().lfcStartHandler());
1396 }
1398 "no lease backend"));
1399}
1400
1404
1405 // Allow DB reconnect on startup. The database connection parameters specify
1406 // respective details.
1408
1409 // Single stream instance used in all error clauses
1410 std::ostringstream err;
1411
1412 if (!srv) {
1413 err << "Server object not initialized, can't process config.";
1415 }
1416
1418 .arg(srv->redactConfig(config)->str());
1419
1421
1422 // Check that configuration was successful. If not, do not reopen sockets
1423 // and don't bother with DDNS stuff.
1424 try {
1425 int rcode = 0;
1426 isc::config::parseAnswer(rcode, answer);
1427 if (rcode != CONTROL_RESULT_SUCCESS) {
1428 return (answer);
1429 }
1430 } catch (const std::exception& ex) {
1431 err << "Failed to process configuration:" << ex.what();
1433 }
1434
1435 // Enable allocator initialization prior to creating lease manager.
1437
1438 // Re-open lease and host database with new parameters.
1439 try {
1441 std::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, ph::_1);
1442
1444 std::bind(&ControlledDhcpv4Srv::dbRecoveredCallback, srv, ph::_1);
1445
1447 std::bind(&ControlledDhcpv4Srv::dbFailedCallback, srv, ph::_1);
1448
1449 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
1450 string params = "universe=4";
1451 cfg_db->setAppendedParameters(params);
1452 cfg_db->createManagers();
1453 // Reset counters related to connections as all managers have been recreated.
1454 srv->getNetworkState()->resetForDbConnection();
1455 srv->getNetworkState()->resetForLocalCommands();
1456 srv->getNetworkState()->resetForRemoteCommands();
1457 } catch (const std::exception& ex) {
1458 err << "Unable to open database: " << ex.what();
1460 }
1461
1462 // Server will start DDNS communications if its enabled.
1463 try {
1464 srv->startD2();
1465 } catch (const std::exception& ex) {
1466 err << "Error starting DHCP_DDNS client after server reconfiguration: "
1467 << ex.what();
1469 }
1470
1471 // Setup DHCPv4-over-DHCPv6 IPC
1472 try {
1474 } catch (const std::exception& ex) {
1475 err << "error starting DHCPv4-over-DHCPv6 IPC "
1476 " after server reconfiguration: " << ex.what();
1478 }
1479
1480 // Configure DHCP packet queueing
1481 try {
1483 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
1484 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
1486 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
1487 }
1488
1489 } catch (const std::exception& ex) {
1490 err << "Error setting packet queue controls after server reconfiguration: "
1491 << ex.what();
1493 }
1494
1495 // Configure a callback to shut down the server when the bind socket
1496 // attempts exceeded.
1498 std::bind(&ControlledDhcpv4Srv::openSocketsFailedCallback, srv, ph::_1);
1499
1500 // Configuration may change active interfaces. Therefore, we have to reopen
1501 // sockets according to new configuration. It is possible that this
1502 // operation will fail for some interfaces but the openSockets function
1503 // guards against exceptions and invokes a callback function to
1504 // log warnings. Since we allow that this fails for some interfaces there
1505 // is no need to rollback configuration if socket fails to open on any
1506 // of the interfaces.
1507 CfgMgr::instance().getStagingCfg()->getCfgIface()->
1508 openSockets(AF_INET, srv->getServerPort(),
1510
1511 // Install the timers for handling leases reclamation.
1512 try {
1513 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
1514 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
1515 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
1516 server_);
1517
1518 } catch (const std::exception& ex) {
1519 err << "unable to setup timers for periodically running the"
1520 " reclamation of the expired leases: "
1521 << ex.what() << ".";
1523 }
1524
1525 // Setup config backend polling, if configured for it.
1526 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
1527 if (ctl_info) {
1528 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
1529 // Only schedule the CB fetch timer if the fetch wait time is greater
1530 // than 0.
1531 if (fetch_time > 0) {
1532 // When we run unit tests, we want to use milliseconds unit for the
1533 // specified interval. Otherwise, we use seconds. Note that using
1534 // milliseconds as a unit in unit tests prevents us from waiting 1
1535 // second on more before the timer goes off. Instead, we wait one
1536 // millisecond which significantly reduces the test time.
1537 if (!server_->inTestMode()) {
1538 fetch_time = 1000 * fetch_time;
1539 }
1540
1541 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1543 registerTimer("Dhcp4CBFetchTimer",
1544 std::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
1545 server_, CfgMgr::instance().getStagingCfg(),
1546 failure_count),
1547 fetch_time,
1549 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1550 }
1551 }
1552
1553 // Finally, we can commit runtime option definitions in libdhcp++. This is
1554 // exception free.
1556
1558 if (notify_libraries) {
1559 return (notify_libraries);
1560 }
1561
1562 // Apply multi threading settings.
1563 // @note These settings are applied/updated only if no errors occur while
1564 // applying the new configuration.
1565 // @todo This should be fixed.
1566 try {
1567 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1568 } catch (const std::exception& ex) {
1569 err << "Error applying multi threading settings: "
1570 << ex.what();
1572 }
1573
1574 return (answer);
1575}
1576
1580 // This hook point notifies hooks libraries that the configuration of the
1581 // DHCPv4 server has completed. It provides the hook library with the pointer
1582 // to the common IO service object, new server configuration in the JSON
1583 // format and with the pointer to the configuration storage where the
1584 // parsed configuration is stored.
1585 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp4_srv_configured_)) {
1587
1588 callout_handle->setArgument("io_context", srv->getIOService());
1589 callout_handle->setArgument("network_state", srv->getNetworkState());
1590 callout_handle->setArgument("json_config", config);
1591 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1592
1593 HooksManager::callCallouts(Hooks.hooks_index_dhcp4_srv_configured_,
1594 *callout_handle);
1595
1596 // If next step is DROP, report a configuration error.
1597 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1598 string error;
1599 try {
1600 callout_handle->getArgument("error", error);
1601 } catch (NoSuchArgument const& ex) {
1602 error = "unknown error";
1603 }
1605 }
1606 }
1607
1608 return (ConstElementPtr());
1609}
1610
1614
1615 if (!srv) {
1617 "Server object not initialized, can't process config.");
1618 return (no_srv);
1619 }
1620
1622 .arg(srv->redactConfig(config)->str());
1623
1624 return (configureDhcp4Server(*srv, config, true));
1625}
1626
1627ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
1628 uint16_t client_port /*= 0*/)
1629 : Dhcpv4Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1630 if (getInstance()) {
1632 "There is another Dhcpv4Srv instance already.");
1633 }
1634 server_ = this; // remember this instance for later use in handlers
1635
1636 // ProcessSpawn uses IO service to handle signal set events.
1638
1639 // TimerMgr uses IO service to run asynchronous timers.
1640 TimerMgr::instance()->setIOService(getIOService());
1641
1642 // Command managers use IO service to run asynchronous socket operations.
1645
1646 // Set the HTTP authentication default realm.
1648
1649 // Set the HTTP supported service.
1651
1652 // DatabaseConnection uses IO service to run asynchronous timers.
1654
1655 // These are the commands always supported by the DHCPv4 server.
1656 // Please keep the list in alphabetic order.
1657 CommandMgr::instance().registerCommand("build-report",
1658 std::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1659
1660 CommandMgr::instance().registerCommand("config-backend-pull",
1661 std::bind(&ControlledDhcpv4Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1662
1664 std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1665
1666 CommandMgr::instance().registerCommand("config-hash-get",
1667 std::bind(&ControlledDhcpv4Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1668
1669 CommandMgr::instance().registerCommand("config-reload",
1670 std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1671
1673 std::bind(&ControlledDhcpv4Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1674
1675 CommandMgr::instance().registerCommand("config-test",
1676 std::bind(&ControlledDhcpv4Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1677
1678 CommandMgr::instance().registerCommand("config-write",
1679 std::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1680
1681 CommandMgr::instance().registerCommand("dhcp-enable",
1682 std::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1683
1684 CommandMgr::instance().registerCommand("dhcp-disable",
1685 std::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1686
1687 CommandMgr::instance().registerCommand("interface-add",
1688 std::bind(&ControlledDhcpv4Srv::commandInterfaceAddHandler, this, ph::_1, ph::_2));
1689
1690 CommandMgr::instance().registerCommand("interface-list",
1691 std::bind(&ControlledDhcpv4Srv::commandInterfaceListHandler, this, ph::_1, ph::_2));
1692
1693 CommandMgr::instance().registerCommand("interface-redetect",
1694 std::bind(&ControlledDhcpv4Srv::commandInterfaceRedetectHandler, this, ph::_1, ph::_2));
1695
1696 CommandMgr::instance().registerCommand("kea-lfc-start",
1697 std::bind(&ControlledDhcpv4Srv::commandLfcStartHandler, this, ph::_1, ph::_2));
1698
1699 CommandMgr::instance().registerCommand("leases-reclaim",
1700 std::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1701
1702 CommandMgr::instance().registerCommand("subnet4-select-test",
1703 std::bind(&ControlledDhcpv4Srv::commandSubnet4SelectTestHandler, this, ph::_1, ph::_2));
1704
1705 CommandMgr::instance().registerCommand("subnet4o6-select-test",
1706 std::bind(&ControlledDhcpv4Srv::commandSubnet4o6SelectTestHandler, this, ph::_1, ph::_2));
1707
1708 CommandMgr::instance().registerCommand("server-tag-get",
1709 std::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1710
1712 std::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1713
1715 std::bind(&ControlledDhcpv4Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1716
1717 CommandMgr::instance().registerCommand("version-get",
1718 std::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1719
1720 // Register statistic related commands
1721 CommandMgr::instance().registerCommand("statistic-get",
1722 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1723
1724 CommandMgr::instance().registerCommand("statistic-reset",
1725 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1726
1727 CommandMgr::instance().registerCommand("statistic-remove",
1728 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1729
1730 CommandMgr::instance().registerCommand("statistic-get-all",
1731 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1732
1733 CommandMgr::instance().registerCommand("statistic-global-get-all",
1734 std::bind(&StatsMgr::statisticGlobalGetAllHandler, ph::_1, ph::_2));
1735
1736 CommandMgr::instance().registerCommand("statistic-reset-all",
1737 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1738
1739 CommandMgr::instance().registerCommand("statistic-remove-all",
1740 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1741
1742 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1743 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1744
1745 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1746 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1747
1748 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1749 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1750
1751 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1753}
1754
1756 setExitValue(exit_value);
1757 getIOService()->stop(); // Stop ASIO transmissions
1758 shutdown(); // Initiate DHCPv4 shutdown procedure.
1759}
1760
1762 try {
1763 MultiThreadingMgr::instance().apply(false, 0, 0);
1766
1767 // The closure captures either a shared pointer (memory leak)
1768 // or a raw pointer (pointing to a deleted object).
1772
1773 timer_mgr_->unregisterTimers();
1774
1775 cleanup();
1776
1777 // Close command sockets.
1780
1781 // Deregister any registered commands (please keep in alphabetic order)
1782 CommandMgr::instance().deregisterCommand("build-report");
1783 CommandMgr::instance().deregisterCommand("config-backend-pull");
1785 CommandMgr::instance().deregisterCommand("config-hash-get");
1786 CommandMgr::instance().deregisterCommand("config-reload");
1788 CommandMgr::instance().deregisterCommand("config-test");
1789 CommandMgr::instance().deregisterCommand("config-write");
1790 CommandMgr::instance().deregisterCommand("dhcp-disable");
1791 CommandMgr::instance().deregisterCommand("dhcp-enable");
1792 CommandMgr::instance().deregisterCommand("interface-add");
1793 CommandMgr::instance().deregisterCommand("interface-list");
1794 CommandMgr::instance().deregisterCommand("interface-redetect");
1795 CommandMgr::instance().deregisterCommand("kea-lfc-start");
1796 CommandMgr::instance().deregisterCommand("leases-reclaim");
1797 CommandMgr::instance().deregisterCommand("subnet4-select-test");
1798 CommandMgr::instance().deregisterCommand("subnet4o6-select-test");
1799 CommandMgr::instance().deregisterCommand("server-tag-get");
1801 CommandMgr::instance().deregisterCommand("statistic-get");
1802 CommandMgr::instance().deregisterCommand("statistic-get-all");
1803 CommandMgr::instance().deregisterCommand("statistic-global-get-all");
1804 CommandMgr::instance().deregisterCommand("statistic-remove");
1805 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1806 CommandMgr::instance().deregisterCommand("statistic-reset");
1807 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1808 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1809 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1810 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1811 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1813 CommandMgr::instance().deregisterCommand("version-get");
1814
1815 // Reset DatabaseConnection IO service.
1817 } catch (...) {
1818 // Don't want to throw exceptions from the destructor. The server
1819 // is shutting down anyway.
1820 }
1821
1822 server_ = NULL; // forget this instance. There should be no callback anymore
1823 // at this stage anyway.
1824}
1825
1826void
1827ControlledDhcpv4Srv::reclaimExpiredLeases(const size_t max_leases,
1828 const uint16_t timeout,
1829 const bool remove_lease,
1830 const uint16_t max_unwarned_cycles) {
1831 try {
1832 if (network_state_->isServiceEnabled()) {
1833 server_->alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
1834 remove_lease,
1835 max_unwarned_cycles);
1836 } else {
1838 .arg(CfgMgr::instance().getCurrentCfg()->
1839 getCfgExpiration()->getReclaimTimerWaitTime());
1840 }
1841 } catch (const std::exception& ex) {
1843 .arg(ex.what());
1844 }
1845 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1847}
1848
1849void
1850ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1851 if (network_state_->isServiceEnabled()) {
1852 server_->alloc_engine_->deleteExpiredReclaimedLeases4(secs);
1853 }
1854
1855 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1857}
1858
1859bool
1860ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1861 if (!db_reconnect_ctl) {
1862 // This should never happen
1864 return (false);
1865 }
1866
1867 // Disable service until the connection is recovered.
1868 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1869 db_reconnect_ctl->alterServiceState()) {
1870 network_state_->disableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1871 }
1872
1874 .arg(db_reconnect_ctl->id())
1875 .arg(db_reconnect_ctl->timerName());;
1876
1877 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1878 // return false.
1879 if (!db_reconnect_ctl->retriesLeft() ||
1880 !db_reconnect_ctl->retryInterval()) {
1882 .arg(db_reconnect_ctl->retriesLeft())
1883 .arg(db_reconnect_ctl->retryInterval())
1884 .arg(db_reconnect_ctl->id())
1885 .arg(db_reconnect_ctl->timerName());
1886 if (db_reconnect_ctl->exitOnFailure()) {
1887 shutdownServer(EXIT_FAILURE);
1888 }
1889 return (false);
1890 }
1891
1892 return (true);
1893}
1894
1895bool
1896ControlledDhcpv4Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1897 if (!db_reconnect_ctl) {
1898 // This should never happen
1900 return (false);
1901 }
1902
1903 // Enable service after the connection is recovered.
1904 if (db_reconnect_ctl->retriesLeft() != db_reconnect_ctl->maxRetries() &&
1905 db_reconnect_ctl->alterServiceState()) {
1906 network_state_->enableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1907 }
1908
1910 .arg(db_reconnect_ctl->id())
1911 .arg(db_reconnect_ctl->timerName());
1912
1913 db_reconnect_ctl->resetRetries();
1914
1915 return (true);
1916}
1917
1918bool
1919ControlledDhcpv4Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1920 if (!db_reconnect_ctl) {
1921 // This should never happen
1923 return (false);
1924 }
1925
1927 .arg(db_reconnect_ctl->maxRetries())
1928 .arg(db_reconnect_ctl->id())
1929 .arg(db_reconnect_ctl->timerName());
1930
1931 if (db_reconnect_ctl->exitOnFailure()) {
1932 shutdownServer(EXIT_FAILURE);
1933 }
1934
1935 return (true);
1936}
1937
1938void
1939ControlledDhcpv4Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1940 if (!reconnect_ctl) {
1941 // This should never happen
1943 return;
1944 }
1945
1946 if (reconnect_ctl->exitOnFailure()) {
1948 .arg(reconnect_ctl->maxRetries());
1949 shutdownServer(EXIT_FAILURE);
1950 } else {
1952 .arg(reconnect_ctl->maxRetries());
1953 }
1954}
1955
1956void
1957ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1958 boost::shared_ptr<unsigned> failure_count) {
1959 // stop thread pool (if running)
1960 MultiThreadingCriticalSection cs;
1961
1962 try {
1963 // Fetch any configuration backend updates since our last fetch.
1964 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1965 CBControlDHCPv4::FetchMode::FETCH_UPDATE);
1966 (*failure_count) = 0;
1967
1968 } catch (const std::exception& ex) {
1970 .arg(ex.what());
1971
1972 // We allow at most 10 consecutive failures after which we stop
1973 // making further attempts to fetch the configuration updates.
1974 // Let's return without re-scheduling the timer.
1975 if (++(*failure_count) > 10) {
1978 return;
1979 }
1980 }
1981
1982 // Reschedule the timer to fetch new updates or re-try if
1983 // the previous attempt resulted in an error.
1984 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1985 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1986 }
1987}
1988
1989} // namespace dhcp
1990} // namespace isc
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.
virtual isc::data::ConstElementPtr processCommand(const isc::data::ConstElementPtr &cmd)
Triggers command processing.
void registerCommand(const std::string &cmd, CommandHandler handler)
Registers specified command handler for a given command.
static std::string getHash(const isc::data::ConstElementPtr &config)
returns a hash of a given Element structure
void deregisterCommand(const std::string &cmd)
Deregisters specified command handler.
static CommandMgr & instance()
CommandMgr is a singleton class.
static std::string DEFAULT_AUTHENTICATION_REALM
Default HTTP authentication realm.
static std::string SUPPORTED_SERVICE
Supported service.
void closeCommandSockets()
Close http control sockets.
static HttpCommandMgr & instance()
HttpCommandMgr is a singleton class.
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the http command manager.
static UnixCommandMgr & instance()
UnixCommandMgr is a singleton class.
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the unix command manager.
void closeCommandSockets()
Shuts down any open unix control sockets.
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:299
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:354
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:349
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.
Represents selection of interfaces for DHCP server.
Definition cfg_iface.h:131
static OpenSocketsFailedCallback open_sockets_failed_callback_
Optional callback function to invoke if all retries of the opening sockets fail.
Definition cfg_iface.h:369
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition cfgmgr.cc:121
void commit()
Commits the staging configuration.
Definition cfgmgr.cc:93
void clearStagingConfiguration()
Remove staging configuration.
Definition cfgmgr.cc:88
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
static void apply(data::ConstElementPtr value)
apply multi threading configuration
void insert(const ClientClass &class_name)
Insert an element.
Definition classify.h:160
Controlled version of the DHCPv4 server.
isc::data::ConstElementPtr commandConfigReloadHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'config-reload' command.
isc::data::ConstElementPtr commandLeasesReclaimHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'leases-reclaim' command.
isc::data::ConstElementPtr commandLfcStartHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'kea-lfc-start' command
virtual ~ControlledDhcpv4Srv()
Destructor.
isc::data::ConstElementPtr commandConfigSetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'config-set' command
isc::data::ConstElementPtr commandStatusGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'status-get' command
isc::data::ConstElementPtr commandConfigGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'config-get' command
isc::data::ConstElementPtr commandInterfaceRedetectHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'interface-redetect' command.
bool getShutdown() const
Return the server shutdown flag value.
isc::data::ConstElementPtr commandConfigWriteHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'config-write' command
static isc::data::ConstElementPtr finishConfigHookLibraries(isc::data::ConstElementPtr config)
Configuration checker for hook libraries.
isc::data::ConstElementPtr commandInterfaceListHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'interface-list' command.
isc::data::ConstElementPtr commandShutdownHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'shutdown' command.
isc::data::ConstElementPtr loadConfigFile(const std::string &file_name)
Configure DHCPv4 server using the configuration file specified.
void cleanup()
Performs cleanup, immediately before termination.
isc::data::ConstElementPtr commandSubnet4o6SelectTestHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'subnet4o6-select-test' command.
isc::data::ConstElementPtr commandBuildReportHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'build-report' command
ControlledDhcpv4Srv(uint16_t server_port=DHCP4_SERVER_PORT, uint16_t client_port=0)
Constructor.
isc::data::ConstElementPtr commandConfigTestHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'config-test' command
isc::data::ConstElementPtr commandDhcpEnableHandler(const std::string &command, isc::data::ConstElementPtr args)
A handler for processing 'dhcp-enable' command.
isc::data::ConstElementPtr commandConfigBackendPullHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for config-backend-pull command
isc::data::ConstElementPtr commandVersionGetHandler(const std::string &command, isc::data::ConstElementPtr args)
@Brief handler for processing 'version-get' command
static isc::data::ConstElementPtr checkConfig(isc::data::ConstElementPtr config)
Configuration checker.
isc::data::ConstElementPtr commandServerTagGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for server-tag-get command
void init(const std::string &config_file)
Initializes the server.
isc::data::ConstElementPtr commandStatisticSetMaxSampleCountAllHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'statistic-sample-count-set-all' command
isc::data::ConstElementPtr commandInterfaceAddHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'interface-add' command.
isc::data::ConstElementPtr commandSubnet4SelectTestHandler(const std::string &command, isc::data::ConstElementPtr args)
Handler for processing 'subnet4-select-test' command.
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.
isc::data::ConstElementPtr commandConfigHashGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'config-hash-get' command
isc::data::ConstElementPtr commandStatisticSetMaxSampleAgeAllHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for processing 'statistic-sample-age-set-all' command
isc::data::ConstElementPtr commandDhcpDisableHandler(const std::string &command, isc::data::ConstElementPtr args)
A handler for processing 'dhcp-disable' command.
static Dhcp4to6Ipc & instance()
Returns pointer to the sole instance of Dhcp4to6Ipc.
virtual void open()
Open communication socket.
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
Dhcpv4Srv(uint16_t server_port=DHCP4_SERVER_PORT, uint16_t client_port=0, const bool use_bcast=true, const bool direct_response_desired=true)
Default constructor.
Definition dhcp4_srv.cc:677
void shutdown() override
Instructs the server to shut down.
Definition dhcp4_srv.cc:784
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
Definition dhcp4_srv.h:318
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
Definition dhcp4_srv.h:1272
NetworkStatePtr & getNetworkState()
Returns pointer to the network state used by the server.
Definition dhcp4_srv.h:323
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
volatile bool shutdown_
Indicates if shutdown is in progress.
Definition dhcp4_srv.h:1266
bool useBroadcast() const
Return bool value indicating that broadcast flags should be set on sockets.
Definition dhcp4_srv.h:463
NetworkStatePtr network_state_
Holds information about disabled DHCP service and/or disabled subnet/network scopes.
Definition dhcp4_srv.h:1279
uint16_t getServerPort() const
Get UDP port on which server should listen.
static void create()
Creates new instance of the HostMgr.
Definition host_mgr.cc:52
size_t size() const
Return the number of interfaces.
Definition iface_mgr.h:635
const IfaceCollection & getIfaces()
Returns container with all interfaces.
Definition iface_mgr.h:942
void detectIfaces(bool update_only=false)
Detects network interfaces.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:52
Parser for the configuration of interfaces.
void parseInterfacesList(const CfgIfacePtr &cfg_iface, isc::data::ConstElementPtr ifaces_list)
parses interfaces-list structure
static TrackingLeaseMgr & instance()
Return current lease manager.
static bool init_allocators_
Flag which indicates if allocators must be initialized.
static void destroy()
Destroy lease manager.
static bool haveInstance()
Indicates if the lease manager has been instantiated.
virtual data::ElementPtr getStatus() const
Return status information.
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition libdhcp++.cc:248
Concrete implementation of a lease database backend using flat file.
static bool isLFCProcessRunning(const std::string file_name, Universe u)
Check if LFC is running.
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).
RAII class creating a critical section for the receiver thread.
Definition iface_mgr.h:1867
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:107
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:269
isc::asiolink::IOSignalSetPtr signal_set_
A pointer to the object installing custom signal handlers.
Definition daemon.h:272
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition daemon.h:278
void checkWriteConfigFile(std::string &file)
Checks the to-be-written configuration file name.
Definition daemon.cc:132
void setExitValue(int value)
Sets the exit value.
Definition daemon.h:242
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition daemon.cc:297
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.
void apply(bool enabled, uint32_t thread_count, uint32_t queue_size)
Apply the multi-threading related settings.
This file contains several functions and constants that are used for handling commands and responses ...
Contains declarations for loggers used by the DHCPv4 server component.
Dhcp4Hooks Hooks
Definition dhcp4_srv.cc:213
Defines the Dhcp4o6Ipc class.
@ D6O_INTERFACE_ID
Definition dhcp6.h:38
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
isc::data::ConstElementPtr statisticSetMaxSampleCountAllHandler(const isc::data::ConstElementPtr &params)
Handles statistic-sample-count-set-all command.
static isc::data::ConstElementPtr statisticResetHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-reset command.
static isc::data::ConstElementPtr statisticGetAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-get-all command.
static isc::data::ConstElementPtr statisticRemoveHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-remove command.
static isc::data::ConstElementPtr statisticGetHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-get command.
static isc::data::ConstElementPtr statisticGlobalGetAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-global-get-all command.
isc::data::ConstElementPtr statisticSetMaxSampleAgeAllHandler(const isc::data::ConstElementPtr &params)
Handles statistic-sample-age-set-all command.
static isc::data::ConstElementPtr statisticResetAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-reset-all command.
static isc::data::ConstElementPtr statisticSetMaxSampleAgeHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-sample-age-set command.
static isc::data::ConstElementPtr statisticRemoveAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-remove-all command.
static isc::data::ConstElementPtr statisticSetMaxSampleCountHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-sample-count-set command.
uint32_t getMaxSampleCountDefault() const
Get default count limit.
const StatsDuration & getMaxSampleAgeDefault() const
Get default duration limit.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
#define LOG_FATAL(LOGGER, MESSAGE)
Macro to conveniently test fatal output and log it.
Definition macros.h:38
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Parses a standard config/command level answer and returns arguments or text status code.
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(const int status_code, const std::string &text, const ConstElementPtr &arg)
Creates a standard config/command level answer message.
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
const int CONTROL_RESULT_COMMAND_UNSUPPORTED
Status code indicating that the specified command is not supported.
const int CONTROL_RESULT_FATAL_ERROR
Status code indicating that the command was unsuccessful and the configuration could not be reverted ...
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
@ error
Definition db_log.h:124
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< const Subnet4 > ConstSubnet4Ptr
A const pointer to a Subnet4 object.
Definition subnet.h:455
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:555
const isc::log::MessageID DHCP4_DB_RECONNECT_NO_DB_CTL
boost::shared_ptr< CfgIface > CfgIfacePtr
A pointer to the CfgIface .
Definition cfg_iface.h:522
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_FATAL_OPEN_SOCKETS_FAILED
const isc::log::MessageID DHCP4_DB_RECONNECT_DISABLED
const isc::log::MessageID DHCP4_CONFIG_UNRECOVERABLE_ERROR
const int DBG_DHCP4_BASIC
Debug level used to trace basic operations within the code.
Definition dhcp4_log.h:33
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
const isc::log::MessageID DHCP4_RECLAIM_EXPIRED_LEASES_SKIPPED
isc::log::Logger dhcp4_logger(DHCP4_APP_LOGGER_NAME)
Base logger for DHCPv4 server.
Definition dhcp4_log.h:90
boost::shared_ptr< SharedNetwork4 > SharedNetwork4Ptr
Pointer to SharedNetwork4 object.
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
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
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
void decodeFormattedHexString(const string &hex_string, vector< uint8_t > &binary)
Converts a formatted string of hexadecimal digits into a vector.
Definition str.cc:212
vector< uint8_t > quotedStringToBinary(const string &quoted_string)
Converts a string in quotes into vector.
Definition str.cc:139
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.
Subnet selector used to specify parameters used to select a subnet.
asiolink::IOAddress local_address_
Address on which the message was received.
bool dhcp4o6_
Specifies if the packet is DHCP4o6.
asiolink::IOAddress option_select_
RAI link select or subnet select option.
std::string iface_name_
Name of the interface on which the message was received.
asiolink::IOAddress ciaddr_
ciaddr from the client's message.
ClientClasses client_classes_
Classes that the client belongs to.
asiolink::IOAddress remote_address_
Source address of the message.
OptionPtr interface_id_
Interface id option.
asiolink::IOAddress first_relay_linkaddr_
First relay link address.
asiolink::IOAddress giaddr_
giaddr from the client's message.