Kea 3.3.1
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 if (rcode == CONTROL_RESULT_FATAL_ERROR) {
182 } else {
183 isc_throw(isc::BadValue, reason);
184 }
185 }
186 } catch (const isc::FatalException&) {
187 throw;
188 } catch (const std::exception& ex) {
189 // If configuration failed at any stage, we drop the staging
190 // configuration and continue to use the previous one.
192
194 .arg(file_name).arg(ex.what());
195 isc_throw(isc::BadValue, "configuration error using file '"
196 << file_name << "': " << ex.what());
197 }
198
200 .arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
201 .arg(MultiThreadingMgr::instance().getThreadPoolSize())
202 .arg(MultiThreadingMgr::instance().getPacketQueueSize());
203
204 return (result);
205}
206
207bool
211
216 return (createAnswer(CONTROL_RESULT_ERROR, "Shutdown failure."));
217 }
218
219 int exit_value = 0;
220 if (args) {
221 // @todo Should we go ahead and shutdown even if the args are invalid?
222 if (args->getType() != Element::map) {
223 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
224 }
225
226 ConstElementPtr param = args->get("exit-value");
227 if (param) {
228 if (param->getType() != Element::integer) {
230 "parameter 'exit-value' is not an integer"));
231 }
232
233 exit_value = param->intValue();
234 }
235 }
236
238 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
239}
240
243 ConstElementPtr /*args*/) {
244 if (!IfaceMgr::instance().isMainThread()) {
246 "Illegal operation executing 'config-reload' on a different thread than main thread"));
247 }
248 // Get configuration file name.
250 try {
252 auto result = loadConfigFile(file);
254 return (result);
255 } catch (const FatalException& ex) {
257 .arg(file);
258 if (Daemon::getShutdownOnFailure()) {
259 shutdownServer(EXIT_FAILURE);
260 }
262 "Config reload failed: " + string(ex.what())));
263 } catch (const std::exception& ex) {
264 // Log the unsuccessful reconfiguration. The reason for failure
265 // should be already logged. Don't rethrow an exception so as
266 // the server keeps working.
268 .arg(file);
270 "Config reload failed: " + string(ex.what())));
271 }
272}
273
276 ConstElementPtr /*args*/) {
278 string hash = BaseCommandMgr::getHash(config);
279 config->set("hash", Element::create(hash));
280
282}
283
286 ConstElementPtr /*args*/) {
288
289 string hash = BaseCommandMgr::getHash(config);
290
292 params->set("hash", Element::create(hash));
293 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
294}
295
298 ConstElementPtr args) {
299 string filename;
300
301 if (args) {
302 if (args->getType() != Element::map) {
303 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
304 }
305 ConstElementPtr filename_param = args->get("filename");
306 if (filename_param) {
307 if (filename_param->getType() != Element::string) {
309 "passed parameter 'filename' is not a string"));
310 }
311 filename = filename_param->stringValue();
312 }
313 }
314
315 if (filename.empty()) {
316 // filename parameter was not specified, so let's use whatever we remember
317 // from the command-line
318 filename = getConfigFile();
319 if (filename.empty()) {
320 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
321 "Please specify filename explicitly."));
322 }
323 } else {
324 try {
325 checkWriteConfigFile(filename);
326 } catch (const isc::Exception& ex) {
327 std::ostringstream msg;
328 msg << "not allowed to write config into " << filename
329 << ": " << ex.what();
330 return (createAnswer(CONTROL_RESULT_ERROR, msg.str()));
331 }
332 }
333
334 // Ok, it's time to write the file.
335 size_t size = 0;
336 try {
337 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
338 size = writeConfigFile(filename, cfg);
339 } catch (const isc::Exception& ex) {
340 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during config-write: ")
341 + ex.what()));
342 }
343 if (size == 0) {
344 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
345 + filename));
346 }
347
348 // Ok, it's time to return the successful response.
350 params->set("size", Element::create(static_cast<long long>(size)));
351 params->set("filename", Element::create(filename));
352
353 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
354 + filename + " successful", params));
355}
356
359 ConstElementPtr args) {
360 if (!IfaceMgr::instance().isMainThread()) {
362 "Illegal operation executing 'config-set' on a different thread than main thread"));
363 }
364 const int status_code = CONTROL_RESULT_ERROR;
365 ConstElementPtr dhcp4;
366 string message;
367
368 // Command arguments are expected to be:
369 // { "Dhcp4": { ... } }
370 if (!args) {
371 message = "Missing mandatory 'arguments' parameter.";
372 } else {
373 dhcp4 = args->get("Dhcp4");
374 if (!dhcp4) {
375 message = "Missing mandatory 'Dhcp4' parameter.";
376 } else if (dhcp4->getType() != Element::map) {
377 message = "'Dhcp4' parameter expected to be a map.";
378 }
379 }
380
381 // Check unsupported objects.
382 if (message.empty()) {
383 for (auto const& obj : args->mapValue()) {
384 const string& obj_name = obj.first;
385 if (obj_name != "Dhcp4") {
387 .arg(obj_name);
388 if (message.empty()) {
389 message = "Unsupported '" + obj_name + "' parameter";
390 } else {
391 message += " (and '" + obj_name + "')";
392 }
393 }
394 }
395 if (!message.empty()) {
396 message += ".";
397 }
398 }
399
400 if (!message.empty()) {
401 // Something is amiss with arguments, return a failure response.
402 ConstElementPtr result = isc::config::createAnswer(status_code,
403 message);
404 return (result);
405 }
406
408 (LeaseMgrFactory::instance().getType() == "memfile")) {
410 auto file_name = mgr.getLeaseFilePath(Memfile_LeaseMgr::V4);
413 "Can not update configuration while lease file cleanup process is running."));
414 }
415 }
416
417 // stop thread pool (if running)
419
420 // We are starting the configuration process so we should remove any
421 // staging configuration that has been created during previous
422 // configuration attempts.
424
425 // Parse the logger configuration explicitly into the staging config.
426 // Note this does not alter the current loggers, they remain in
427 // effect until we apply the logging config below. If no logging
428 // is supplied logging will revert to default logging.
429 Daemon::configureLogger(dhcp4, CfgMgr::instance().getStagingCfg());
430
431 // Let's apply the new logging. We do it early, so we'll be able to print
432 // out what exactly is wrong with the new config in case of problems.
433 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
434
435 // Now we configure the server proper.
436 ConstElementPtr result = processConfig(dhcp4);
437
438 // If the configuration parsed successfully, apply the new logger
439 // configuration and then commit the new configuration. We apply
440 // the logging first in case there's a configuration failure.
441 int rcode = 0;
442 isc::config::parseAnswer(rcode, result);
443 if (getShutdown() && (rcode == CONTROL_RESULT_SUCCESS)) {
444 // Do not return success when a fatal error was triggered.
446 message = "Reconfiguration triggered a fatal error: shutting down.";
447 result = isc::config::createAnswer(rcode, message);
448 }
449 if (rcode == CONTROL_RESULT_SUCCESS) {
450 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
451
452 // Use new configuration.
454 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
455 // Ok, we applied the logging from the upcoming configuration, but
456 // there were problems with the config. As such, we need to back off
457 // and revert to the previous logging configuration. This is not done if
458 // sequence == 0, because that would mean always reverting to stdout by
459 // default, and it is arguably more helpful to have the error in a
460 // potential file or syslog configured in the upcoming configuration.
461 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
462
463 if (rcode == CONTROL_RESULT_FATAL_ERROR) {
464 // Not initial configuration so someone can believe we reverted
465 // to the previous configuration. It is not the case so be clear
466 // about this.
468 }
469 }
470
472 try {
473 // Handle events registered by hooks using external IOService objects.
475 } catch (const std::exception& ex) {
476 if (rcode == CONTROL_RESULT_FATAL_ERROR) {
477 if (Daemon::getShutdownOnFailure()) {
478 shutdownServer(EXIT_FAILURE);
479 }
480 return (result);
481 }
482 std::ostringstream err;
483 err << "Error initializing hooks: "
484 << ex.what();
486 }
487
488 if (rcode == CONTROL_RESULT_FATAL_ERROR && Daemon::getShutdownOnFailure()) {
489 shutdownServer(EXIT_FAILURE);
490 }
491
492 return (result);
493}
494
497 ConstElementPtr args) {
498 if (!IfaceMgr::instance().isMainThread()) {
500 "Illegal operation executing 'config-test' on a different thread than main thread"));
501 }
502 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
503 ConstElementPtr dhcp4;
504 string message;
505
506 // Command arguments are expected to be:
507 // { "Dhcp4": { ... } }
508 if (!args) {
509 message = "Missing mandatory 'arguments' parameter.";
510 } else {
511 dhcp4 = args->get("Dhcp4");
512 if (!dhcp4) {
513 message = "Missing mandatory 'Dhcp4' parameter.";
514 } else if (dhcp4->getType() != Element::map) {
515 message = "'Dhcp4' parameter expected to be a map.";
516 }
517 }
518
519 // Check unsupported objects.
520 if (message.empty()) {
521 for (auto const& obj : args->mapValue()) {
522 const string& obj_name = obj.first;
523 if (obj_name != "Dhcp4") {
525 .arg(obj_name);
526 if (message.empty()) {
527 message = "Unsupported '" + obj_name + "' parameter";
528 } else {
529 message += " (and '" + obj_name + "')";
530 }
531 }
532 }
533 if (!message.empty()) {
534 message += ".";
535 }
536 }
537
538 if (!message.empty()) {
539 // Something is amiss with arguments, return a failure response.
540 ConstElementPtr result = isc::config::createAnswer(status_code,
541 message);
542 return (result);
543 }
544
545 // stop thread pool (if running)
547
548 // We are starting the configuration process so we should remove any
549 // staging configuration that has been created during previous
550 // configuration attempts.
552
553 // Now we check the server proper.
554 return (checkConfig(dhcp4));
555}
556
559 ConstElementPtr args) {
560 std::ostringstream message;
561 int64_t max_period = 0;
562 std::string origin;
563
564 // If the args map does not contain 'origin' parameter, the default type
565 // will be used (user command).
566 auto type = NetworkState::USER_COMMAND;
567
568 // Parse arguments to see if the 'max-period' or 'origin' parameters have
569 // been specified.
570 if (args) {
571 // Arguments must be a map.
572 if (args->getType() != Element::map) {
573 message << "arguments for the 'dhcp-disable' command must be a map";
574
575 } else {
576 ConstElementPtr max_period_element = args->get("max-period");
577 // max-period is optional.
578 if (max_period_element) {
579 // It must be an integer, if specified.
580 if (max_period_element->getType() != Element::integer) {
581 message << "'max-period' argument must be a number";
582
583 } else {
584 // It must be positive integer.
585 max_period = max_period_element->intValue();
586 if (max_period <= 0) {
587 message << "'max-period' must be positive integer";
588 }
589 }
590 }
591 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
592 // stable release. However, the 'origin' is kept for backward compatibility
593 // with Kea versions before 2.5.8. It is common to receive both parameters
594 // because HA hook library sends both in case the partner server hasn't been
595 // upgraded to the new version. The 'origin-id' takes precedence over the
596 // 'origin'.
597 ConstElementPtr origin_id_element = args->get("origin-id");
598 ConstElementPtr origin_element = args->get("origin");
599 // The 'origin-id' and 'origin' arguments are optional.
600 if (origin_id_element) {
601 if (origin_id_element->getType() == Element::integer) {
602 type = origin_id_element->intValue();
603 } else {
604 message << "'origin-id' argument must be a number";
605 }
606 } else if (origin_element) {
607 switch (origin_element->getType()) {
608 case Element::string:
609 origin = origin_element->stringValue();
610 if (origin == "ha-partner") {
612 } else if (origin != "user") {
613 if (origin.empty()) {
614 origin = "(empty string)";
615 }
616 message << "invalid value used for 'origin' parameter: "
617 << origin;
618 }
619 break;
620 case Element::integer:
621 type = origin_element->intValue();
622 break;
623 default:
624 // It must be a string or a number, if specified.
625 message << "'origin' argument must be a string or a number";
626 }
627 }
628 }
629 }
630
631 // No error occurred, so let's disable the service.
632 if (message.tellp() == 0) {
633 message << "DHCPv4 service disabled";
634 if (max_period > 0) {
635 message << " for " << max_period << " seconds";
636
637 // The user specified that the DHCP service should resume not
638 // later than in max-period seconds. If the 'dhcp-enable' command
639 // is not sent, the DHCP service will resume automatically.
640 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
641 type);
642 }
643 network_state_->disableService(type);
644
645 // Success.
646 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
647 }
648
649 // Failure.
650 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
651}
652
655 ConstElementPtr args) {
656 std::ostringstream message;
657 std::string origin;
658
659 // If the args map does not contain 'origin' parameter, the default type
660 // will be used (user command).
661 auto type = NetworkState::USER_COMMAND;
662
663 // Parse arguments to see if the 'origin' parameter has been specified.
664 if (args) {
665 // Arguments must be a map.
666 if (args->getType() != Element::map) {
667 message << "arguments for the 'dhcp-enable' command must be a map";
668
669 } else {
670 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
671 // stable release. However, the 'origin' is kept for backward compatibility
672 // with Kea versions before 2.5.8. It is common to receive both parameters
673 // because HA hook library sends both in case the partner server hasn't been
674 // upgraded to the new version. The 'origin-id' takes precedence over the
675 // 'origin'.
676 ConstElementPtr origin_id_element = args->get("origin-id");
677 ConstElementPtr origin_element = args->get("origin");
678 // The 'origin-id' and 'origin' arguments are optional.
679 if (origin_id_element) {
680 if (origin_id_element->getType() == Element::integer) {
681 type = origin_id_element->intValue();
682 } else {
683 message << "'origin-id' argument must be a number";
684 }
685 } else if (origin_element) {
686 switch (origin_element->getType()) {
687 case Element::string:
688 origin = origin_element->stringValue();
689 if (origin == "ha-partner") {
691 } else if (origin != "user") {
692 if (origin.empty()) {
693 origin = "(empty string)";
694 }
695 message << "invalid value used for 'origin' parameter: "
696 << origin;
697 }
698 break;
699 case Element::integer:
700 type = origin_element->intValue();
701 break;
702 default:
703 // It must be a string or a number, if specified.
704 message << "'origin' argument must be a string or a number";
705 }
706 }
707 }
708 }
709
710 // No error occurred, so let's enable the service.
711 if (message.tellp() == 0) {
712 network_state_->enableService(type);
713
714 // Success.
716 "DHCP service successfully enabled"));
717 }
718
719 // Failure.
720 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
721}
722
727 std::string message;
728 bool error = false;
729 try {
730 ifaces->set("interfaces", IfaceMgr::instance().ifacesToElement());
731 } catch (const std::exception& ex) {
732 error = true;
733 message = ex.what();
734 } catch (...) {
735 error = true;
736 message = "unknown error";
737 }
738
739 ostringstream msg;
740 if (!error) {
742 << " interfaces detected.";
743 return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, msg.str(), ifaces));
744 } else {
745 msg << "Unexpected error while retrieving the list of detected interfaces: " << message;
747 }
748}
749
752 ConstElementPtr args) {
753 if (!IfaceMgr::instance().isMainThread()) {
755 "Illegal operation executing 'interface-redetect' on a different thread than main thread"));
756 }
757 std::string message;
758 bool error = false;
759 try {
760 // stop thread pool (if running)
764 } catch (const std::exception& ex) {
765 error = true;
766 message = ex.what();
767 } catch (...) {
768 error = true;
769 message = "unknown error";
770 }
771
772 ostringstream msg;
773 if (!error) {
775 } else {
776 msg << "Unexpected error while retrieving the list of detected interfaces: " << message;
778 }
779}
780
783 ConstElementPtr args) {
784 if (!IfaceMgr::instance().isMainThread()) {
786 "Illegal operation executing 'interface-add' on a different thread than main thread"));
787 }
788 string message;
789 ConstElementPtr ifaces_config;
790 if (!args) {
791 message = "Missing mandatory 'arguments' parameter.";
792 } else {
793 if (args->getType() != Element::map) {
794 message = "arguments for the 'interface-add' command must be a map";
795 } else {
796 ifaces_config = args->get("interfaces");
797 if (!ifaces_config) {
798 message = "Missing mandatory 'interfaces' map parameter in 'arguments'.";
799 }
800 auto map = args->mapValue();
801 for (auto const& key : map) {
802 if (key.first != "interfaces") {
803 message = "Unsupported '" + key.first + "' map parameter in 'arguments'.";
804 break;
805 }
806 }
807 }
808 }
809
810 if (!message.empty()) {
812 }
813 if (!ifaces_config->size()) {
814 return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Interface configuration successfully updated."));
815 }
816 bool error = false;
817 try {
818 CfgIfacePtr running_cfg = CfgMgr::instance().getCurrentCfg()->getCfgIface();
820 std::set<std::string> seen;
821 auto running_ifaces = running_cfg->toElement()->get("interfaces");
822 if (running_ifaces && (running_ifaces->getType() == Element::list)) {
823 for (auto const& item : running_ifaces->listValue()) {
824 seen.insert(item->stringValue());
825 ifaces->add(item);
826 }
827 }
828 for (auto const& item : ifaces_config->listValue()) {
829 auto const& str = item->stringValue();
830 if (seen.find(str) != seen.end()) {
831 continue;
832 }
833 seen.insert(str);
834 ifaces->add(item);
835 }
836 IfacesConfigParser parser(AF_INET, true);
837 CfgIfacePtr cfg_iface(new CfgIface());
838 parser.parseInterfacesList(cfg_iface, ifaces);
839 running_cfg->update(*cfg_iface);
840 running_cfg->triggerOpenSocketsWithRetry(AF_INET, getServerPort(), useBroadcast());
841 } catch (const std::exception& ex) {
842 error = true;
843 message = ex.what();
844 } catch (...) {
845 error = true;
846 message = "unknown error";
847 }
848
849 ostringstream msg;
850 if (!error) {
851 if (getShutdown()) {
852 return (isc::config::createAnswer(CONTROL_RESULT_FATAL_ERROR, "Interface configuration update triggered a fatal error: shutting down."));
853 }
854 return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Interface configuration successfully updated."));
855 } else {
856 msg << "Updating used interfaces failed: " << message;
858 }
859}
860
864 ElementPtr arguments = Element::createMap();
865 arguments->set("extended", extended);
868 arguments);
869 return (answer);
870}
871
879
882 ConstElementPtr args) {
883 int status_code = CONTROL_RESULT_ERROR;
884 string message;
885
886 // args must be { "remove": <bool> }
887 if (!args) {
888 message = "Missing mandatory 'remove' parameter.";
889 } else {
890 ConstElementPtr remove_name = args->get("remove");
891 if (!remove_name) {
892 message = "Missing mandatory 'remove' parameter.";
893 } else if (remove_name->getType() != Element::boolean) {
894 message = "'remove' parameter expected to be a boolean.";
895 } else {
896 bool remove_lease = remove_name->boolValue();
897 server_->alloc_engine_->reclaimExpiredLeases4(0, 0, remove_lease);
898 status_code = 0;
899 message = "Reclamation of expired leases is complete.";
900 }
901 }
902 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
903 return (answer);
904}
905
908 ConstElementPtr args) {
909 if (!args) {
910 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
911 }
912 if (args->getType() != Element::map) {
913 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
914 }
915 bool ignore_link_sel =
916 CfgMgr::instance().getCurrentCfg()->getIgnoreRAILinkSelection();
917 SubnetSelector selector;
918 for (auto const& entry : args->mapValue()) {
919 ostringstream errmsg;
920 if (entry.first == "interface") {
921 if (entry.second->getType() != Element::string) {
922 errmsg << "'interface' entry must be a string";
923 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
924 }
925 selector.iface_name_ = entry.second->stringValue();
926 continue;
927 } else if (entry.first == "address") {
928 if (entry.second->getType() != Element::string) {
929 errmsg << "'address' entry must be a string";
930 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
931 }
932 try {
933 IOAddress addr(entry.second->stringValue());
934 if (!addr.isV4()) {
935 errmsg << "bad 'address' entry: not IPv4";
936 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
937 }
938 selector.ciaddr_ = addr;
939 continue;
940 } catch (const exception& ex) {
941 errmsg << "bad 'address' entry: " << ex.what();
942 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
943 }
944 } else if (entry.first == "relay") {
945 if (entry.second->getType() != Element::string) {
946 errmsg << "'relay' entry must be a string";
947 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
948 }
949 try {
950 IOAddress addr(entry.second->stringValue());
951 if (!addr.isV4()) {
952 errmsg << "bad 'relay' entry: not IPv4";
953 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
954 }
955 selector.giaddr_ = addr;
956 continue;
957 } catch (const exception& ex) {
958 errmsg << "bad 'relay' entry: " << ex.what();
959 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
960 }
961 } else if (entry.first == "local") {
962 if (entry.second->getType() != Element::string) {
963 errmsg << "'local' entry must be a string";
964 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
965 }
966 try {
967 IOAddress addr(entry.second->stringValue());
968 if (!addr.isV4()) {
969 errmsg << "bad 'local' entry: not IPv4";
970 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
971 }
972 selector.local_address_ = addr;
973 continue;
974 } catch (const exception& ex) {
975 errmsg << "bad 'local' entry: " << ex.what();
976 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
977 }
978 } else if (entry.first == "remote") {
979 if (entry.second->getType() != Element::string) {
980 errmsg << "'remote' entry must be a string";
981 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
982 }
983 try {
984 IOAddress addr(entry.second->stringValue());
985 if (!addr.isV4()) {
986 errmsg << "bad 'remote' entry: not IPv4";
987 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
988 }
989 selector.remote_address_ = addr;
990 continue;
991 } catch (const exception& ex) {
992 errmsg << "bad 'remote' entry: " << ex.what();
993 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
994 }
995 } else if (entry.first == "link") {
996 if (entry.second->getType() != Element::string) {
997 errmsg << "'link' entry must be a string";
998 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
999 }
1000 try {
1001 IOAddress addr(entry.second->stringValue());
1002 if (!addr.isV4()) {
1003 errmsg << "bad 'link' entry: not IPv4";
1004 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1005 }
1006 if (!ignore_link_sel) {
1007 selector.option_select_ = addr;
1008 }
1009 continue;
1010 } catch (const exception& ex) {
1011 errmsg << "bad 'link' entry: " << ex.what();
1012 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1013 }
1014 } else if (entry.first == "subnet") {
1015 // RAI link-selection has precedence over subnet-selection.
1016 if (args->contains("link") && !ignore_link_sel) {
1017 continue;
1018 }
1019 if (entry.second->getType() != Element::string) {
1020 errmsg << "'subnet' entry must be a string";
1021 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1022 }
1023 try {
1024 IOAddress addr(entry.second->stringValue());
1025 if (!addr.isV4()) {
1026 errmsg << "bad 'subnet' entry: not IPv4";
1027 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1028 }
1029 selector.option_select_ = addr;
1030 continue;
1031 } catch (const exception& ex) {
1032 errmsg << "bad 'subnet' entry: " << ex.what();
1033 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1034 }
1035 } else if (entry.first == "classes") {
1036 if (entry.second->getType() != Element::list) {
1038 "'classes' entry must be a list"));
1039 }
1040 for (auto const& item : entry.second->listValue()) {
1041 if (!item || (item->getType() != Element::string)) {
1042 errmsg << "'classes' entry must be a list of strings";
1043 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1044 }
1045 // Skip empty client classes.
1046 if (!item->stringValue().empty()) {
1047 selector.client_classes_.insert(item->stringValue());
1048 }
1049 }
1050 continue;
1051 } else {
1052 errmsg << "unknown entry '" << entry.first << "'";
1053 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1054 }
1055 }
1057 getCfgSubnets4()->selectSubnet(selector);
1058 if (!subnet) {
1059 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
1060 }
1061 SharedNetwork4Ptr network;
1062 subnet->getSharedNetwork(network);
1063 ostringstream msg;
1064 if (network) {
1065 msg << "selected shared network '" << network->getName()
1066 << "' starting with subnet '" << subnet->toText()
1067 << "' id " << subnet->getID();
1068 } else {
1069 msg << "selected subnet '" << subnet->toText()
1070 << "' id " << subnet->getID();
1071 }
1072 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
1073}
1074
1077 ConstElementPtr args) {
1078 if (!args) {
1079 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
1080 }
1081 if (args->getType() != Element::map) {
1082 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
1083 }
1084 SubnetSelector selector;
1085 selector.dhcp4o6_ = true;
1088 for (auto const& entry : args->mapValue()) {
1089 ostringstream errmsg;
1090 if (entry.first == "interface") {
1091 if (entry.second->getType() != Element::string) {
1092 errmsg << "'interface' entry must be a string";
1093 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1094 }
1095 selector.iface_name_ = entry.second->stringValue();
1096 continue;
1097 } if (entry.first == "interface-id") {
1098 if (entry.second->getType() != Element::string) {
1099 errmsg << "'interface-id' entry must be a string";
1100 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1101 }
1102 try {
1103 string str = entry.second->stringValue();
1104 vector<uint8_t> id = util::str::quotedStringToBinary(str);
1105 if (id.empty()) {
1107 }
1108 if (id.empty()) {
1109 errmsg << "'interface-id' must be not empty";
1110 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1111 }
1114 id));
1115 continue;
1116 } catch (...) {
1117 errmsg << "value of 'interface-id' was not recognized";
1118 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1119 }
1120 } else if (entry.first == "address") {
1121 if (entry.second->getType() != Element::string) {
1122 errmsg << "'address' entry must be a string";
1123 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1124 }
1125 try {
1126 IOAddress addr(entry.second->stringValue());
1127 if (!addr.isV4()) {
1128 errmsg << "bad 'address' entry: not IPv4";
1129 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1130 }
1131 selector.ciaddr_ = addr;
1132 continue;
1133 } catch (const exception& ex) {
1134 errmsg << "bad 'address' entry: " << ex.what();
1135 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1136 }
1137 } else if (entry.first == "relay") {
1138 if (entry.second->getType() != Element::string) {
1139 errmsg << "'relay' entry must be a string";
1140 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1141 }
1142 try {
1143 IOAddress addr(entry.second->stringValue());
1144 if (!addr.isV4()) {
1145 errmsg << "bad 'relay' entry: not IPv4";
1146 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1147 }
1148 selector.giaddr_ = addr;
1149 continue;
1150 } catch (const exception& ex) {
1151 errmsg << "bad 'relay' entry: " << ex.what();
1152 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1153 }
1154 } else if (entry.first == "local") {
1155 if (entry.second->getType() != Element::string) {
1156 errmsg << "'local' entry must be a string";
1157 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1158 }
1159 try {
1160 IOAddress addr(entry.second->stringValue());
1161 if (!addr.isV6()) {
1162 errmsg << "bad 'local' entry: not IPv6";
1163 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1164 }
1165 selector.local_address_ = addr;
1166 continue;
1167 } catch (const exception& ex) {
1168 errmsg << "bad 'local' entry: " << ex.what();
1169 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1170 }
1171 } else if (entry.first == "remote") {
1172 if (entry.second->getType() != Element::string) {
1173 errmsg << "'remote' entry must be a string";
1174 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1175 }
1176 try {
1177 IOAddress addr(entry.second->stringValue());
1178 if (!addr.isV6()) {
1179 errmsg << "bad 'remote' entry: not IPv6";
1180 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1181 }
1182 selector.remote_address_ = addr;
1183 continue;
1184 } catch (const exception& ex) {
1185 errmsg << "bad 'remote' entry: " << ex.what();
1186 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1187 }
1188 } else if (entry.first == "link") {
1189 if (entry.second->getType() != Element::string) {
1190 errmsg << "'link' entry must be a string";
1191 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1192 }
1193 try {
1194 IOAddress addr(entry.second->stringValue());
1195 if (!addr.isV6()) {
1196 errmsg << "bad 'link' entry: not IPv6";
1197 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1198 }
1199 selector.first_relay_linkaddr_ = addr;
1200 continue;
1201 } catch (const exception& ex) {
1202 errmsg << "bad 'link' entry: " << ex.what();
1203 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1204 }
1205 } else if (entry.first == "subnet") {
1206 if (entry.second->getType() != Element::string) {
1207 errmsg << "'subnet' entry must be a string";
1208 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1209 }
1210 try {
1211 IOAddress addr(entry.second->stringValue());
1212 if (!addr.isV4()) {
1213 errmsg << "bad 'subnet' entry: not IPv4";
1214 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1215 }
1216 selector.option_select_ = addr;
1217 continue;
1218 } catch (const exception& ex) {
1219 errmsg << "bad 'subnet' entry: " << ex.what();
1220 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1221 }
1222 } else if (entry.first == "classes") {
1223 if (entry.second->getType() != Element::list) {
1225 "'classes' entry must be a list"));
1226 }
1227 for (auto const& item : entry.second->listValue()) {
1228 if (!item || (item->getType() != Element::string)) {
1229 errmsg << "'classes' entry must be a list of strings";
1230 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1231 }
1232 // Skip empty client classes.
1233 if (!item->stringValue().empty()) {
1234 selector.client_classes_.insert(item->stringValue());
1235 }
1236 }
1237 continue;
1238 } else {
1239 errmsg << "unknown entry '" << entry.first << "'";
1240 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1241 }
1242 }
1244 getCfgSubnets4()->selectSubnet4o6(selector);
1245 if (!subnet) {
1246 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
1247 }
1248 SharedNetwork4Ptr network;
1249 subnet->getSharedNetwork(network);
1250 ostringstream msg;
1251 if (network) {
1252 msg << "selected shared network '" << network->getName()
1253 << "' starting with subnet '" << subnet->toText()
1254 << "' id " << subnet->getID();
1255 } else {
1256 msg << "selected subnet '" << subnet->toText()
1257 << "' id " << subnet->getID();
1258 }
1259 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
1260}
1261
1265 const std::string& tag =
1266 CfgMgr::instance().getCurrentCfg()->getServerTag();
1267 ElementPtr response = Element::createMap();
1268 response->set("server-tag", Element::create(tag));
1269
1270 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
1271}
1272
1276 if (!IfaceMgr::instance().isMainThread()) {
1278 "Illegal operation executing 'config-backend-pull' on a different thread than main thread"));
1279 }
1280 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
1281 if (!ctl_info) {
1282 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
1283 }
1284
1285 // stop thread pool (if running)
1287
1288 // Reschedule the periodic CB fetch.
1289 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1290 TimerMgr::instance()->cancel("Dhcp4CBFetchTimer");
1291 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1292 }
1293
1294 // Code from cbFetchUpdates.
1295 // The configuration to use is the current one because this is called
1296 // after the configuration manager commit.
1297 try {
1298 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
1299 auto mode = CBControlDHCPv4::FetchMode::FETCH_UPDATE;
1300 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
1301 } catch (const std::exception& ex) {
1303 .arg(ex.what());
1305 "On demand configuration update failed: " +
1306 string(ex.what())));
1307 }
1309 "On demand configuration update successful."));
1310}
1311
1314 ConstElementPtr /*args*/) {
1315 ElementPtr status = Element::createMap();
1316 status->set("pid", Element::create(static_cast<int>(getpid())));
1317
1318 auto now = boost::posix_time::second_clock::universal_time();
1319 // Sanity check: start_ is always initialized.
1320 if (!start_.is_not_a_date_time()) {
1321 auto uptime = now - start_;
1322 status->set("uptime", Element::create(uptime.total_seconds()));
1323 }
1324
1325 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
1326 if (!last_commit.is_not_a_date_time()) {
1327 auto reload = now - last_commit;
1328 status->set("reload", Element::create(reload.total_seconds()));
1329 }
1330
1331 auto& mt_mgr = MultiThreadingMgr::instance();
1332 if (mt_mgr.getMode()) {
1333 status->set("multi-threading-enabled", Element::create(true));
1334 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
1335 MultiThreadingMgr::instance().getThreadPoolSize())));
1336 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
1337 MultiThreadingMgr::instance().getPacketQueueSize())));
1338 ElementPtr queue_stats = Element::createList();
1339 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
1340 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
1341 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
1342 status->set("packet-queue-statistics", queue_stats);
1343
1344 } else {
1345 status->set("multi-threading-enabled", Element::create(false));
1346 }
1347
1348 // Merge lease manager status.
1349 ElementPtr lm_info;
1352 }
1353 if (lm_info && (lm_info->getType() == Element::map)) {
1354 for (auto const& entry : lm_info->mapValue()) {
1355 status->set(entry.first, entry.second);
1356 }
1357 }
1358
1359 // Iterate through the interfaces and get all the errors.
1360 ElementPtr socket_errors(Element::createList());
1361 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
1362 for (std::string const& error : interface->getErrors()) {
1363 socket_errors->add(Element::create(error));
1364 }
1365 }
1366
1367 // Abstract the information from all sockets into a single status.
1368 ElementPtr sockets(Element::createMap());
1369 if (socket_errors->empty()) {
1370 sockets->set("status", Element::create("ready"));
1371 } else {
1372 ReconnectCtlPtr const reconnect_ctl(
1373 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
1374 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
1375 sockets->set("status", Element::create("retrying"));
1376 } else {
1377 sockets->set("status", Element::create("failed"));
1378 }
1379 sockets->set("errors", socket_errors);
1380 }
1381 status->set("sockets", sockets);
1382
1383 status->set("dhcp-state", network_state_->toElement());
1384
1385 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
1386}
1387
1390 ConstElementPtr args) {
1391 StatsMgr& stats_mgr = StatsMgr::instance();
1393 // Update the default parameter.
1394 long max_samples = stats_mgr.getMaxSampleCountDefault();
1395 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1396 "statistic-default-sample-count", Element::create(max_samples));
1397 return (answer);
1398}
1399
1402 ConstElementPtr args) {
1403 StatsMgr& stats_mgr = StatsMgr::instance();
1404 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleAgeAllHandler(args);
1405 // Update the default parameter.
1406 auto duration = stats_mgr.getMaxSampleAgeDefault();
1407 long max_age = toSeconds(duration);
1408 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1409 "statistic-default-sample-age", Element::create(max_age));
1410 return (answer);
1411}
1412
1416 return (LeaseMgrFactory::instance().lfcStartHandler());
1417 }
1419 "no lease backend"));
1420}
1421
1425
1426 // Allow DB reconnect on startup. The database connection parameters specify
1427 // respective details.
1429
1430 // Single stream instance used in all error clauses
1431 std::ostringstream err;
1432
1433 if (!srv) {
1434 err << "Server object not initialized, can't process config.";
1436 }
1437
1439 .arg(srv->redactConfig(config)->str());
1440
1442
1443 // Check that configuration was successful. If not, do not reopen sockets
1444 // and don't bother with DDNS stuff.
1445 try {
1446 int rcode = 0;
1447 isc::config::parseAnswer(rcode, answer);
1448 if (rcode != CONTROL_RESULT_SUCCESS) {
1449 return (answer);
1450 }
1451 } catch (const std::exception& ex) {
1452 err << "Failed to process configuration:" << ex.what();
1454 }
1455
1456 // Enable allocator initialization prior to creating lease manager.
1458
1459 // Re-open lease and host database with new parameters.
1460 try {
1462 std::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, ph::_1);
1463
1465 std::bind(&ControlledDhcpv4Srv::dbRecoveredCallback, srv, ph::_1);
1466
1468 std::bind(&ControlledDhcpv4Srv::dbFailedCallback, srv, ph::_1);
1469
1470 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
1471 string params = "universe=4";
1472 cfg_db->setAppendedParameters(params);
1473 cfg_db->createManagers();
1474 // Reset counters related to connections as all managers have been recreated.
1475 srv->getNetworkState()->resetForDbConnection();
1476 srv->getNetworkState()->resetForLocalCommands();
1477 srv->getNetworkState()->resetForRemoteCommands();
1478 } catch (const std::exception& ex) {
1479 err << "Unable to open database: " << ex.what();
1481 }
1482
1483 // Server will start DDNS communications if its enabled.
1484 try {
1485 srv->startD2();
1486 } catch (const std::exception& ex) {
1487 err << "Error starting DHCP_DDNS client after server reconfiguration: "
1488 << ex.what();
1490 }
1491
1492 // Setup DHCPv4-over-DHCPv6 IPC
1493 try {
1495 } catch (const std::exception& ex) {
1496 err << "error starting DHCPv4-over-DHCPv6 IPC "
1497 " after server reconfiguration: " << ex.what();
1499 }
1500
1501 // Configure DHCP packet queueing
1502 try {
1504 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
1505 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
1507 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
1508 }
1509
1510 } catch (const std::exception& ex) {
1511 err << "Error setting packet queue controls after server reconfiguration: "
1512 << ex.what();
1514 }
1515
1516 // Configure a callback to shut down the server when the bind socket
1517 // attempts exceeded.
1519 std::bind(&ControlledDhcpv4Srv::openSocketsFailedCallback, srv, ph::_1);
1520
1521 // Configuration may change active interfaces. Therefore, we have to reopen
1522 // sockets according to new configuration. It is possible that this
1523 // operation will fail for some interfaces but the openSockets function
1524 // guards against exceptions and invokes a callback function to
1525 // log warnings. Since we allow that this fails for some interfaces there
1526 // is no need to rollback configuration if socket fails to open on any
1527 // of the interfaces.
1528 CfgMgr::instance().getStagingCfg()->getCfgIface()->
1529 openSockets(AF_INET, srv->getServerPort(),
1531
1532 // Install the timers for handling leases reclamation.
1533 try {
1534 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
1535 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
1536 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
1537 server_);
1538
1539 } catch (const std::exception& ex) {
1540 err << "unable to setup timers for periodically running the"
1541 " reclamation of the expired leases: "
1542 << ex.what() << ".";
1544 }
1545
1546 // Setup config backend polling, if configured for it.
1547 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
1548 if (ctl_info) {
1549 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
1550 // Only schedule the CB fetch timer if the fetch wait time is greater
1551 // than 0.
1552 if (fetch_time > 0) {
1553 // When we run unit tests, we want to use milliseconds unit for the
1554 // specified interval. Otherwise, we use seconds. Note that using
1555 // milliseconds as a unit in unit tests prevents us from waiting 1
1556 // second on more before the timer goes off. Instead, we wait one
1557 // millisecond which significantly reduces the test time.
1558 if (!server_->inTestMode()) {
1559 fetch_time = 1000 * fetch_time;
1560 }
1561
1562 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1564 registerTimer("Dhcp4CBFetchTimer",
1565 std::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
1566 server_, CfgMgr::instance().getStagingCfg(),
1567 failure_count),
1568 fetch_time,
1570 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1571 }
1572 }
1573
1574 // Finally, we can commit runtime option definitions in libdhcp++. This is
1575 // exception free.
1577
1579 if (notify_libraries) {
1580 return (notify_libraries);
1581 }
1582
1583 // Apply multi threading settings.
1584 // @note These settings are applied/updated only if no errors occur while
1585 // applying the new configuration.
1586 // @todo This should be fixed.
1587 try {
1588 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1589 } catch (const std::exception& ex) {
1590 err << "Error applying multi threading settings: "
1591 << ex.what();
1593 }
1594
1595 return (answer);
1596}
1597
1601 // This hook point notifies hooks libraries that the configuration of the
1602 // DHCPv4 server has completed. It provides the hook library with the pointer
1603 // to the common IO service object, new server configuration in the JSON
1604 // format and with the pointer to the configuration storage where the
1605 // parsed configuration is stored.
1606 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp4_srv_configured_)) {
1608
1609 callout_handle->setArgument("io_context", srv->getIOService());
1610 callout_handle->setArgument("network_state", srv->getNetworkState());
1611 callout_handle->setArgument("json_config", config);
1612 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1613
1614 HooksManager::callCallouts(Hooks.hooks_index_dhcp4_srv_configured_,
1615 *callout_handle);
1616
1617 // If next step is DROP, report a configuration error.
1618 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1619 string error;
1620 try {
1621 callout_handle->getArgument("error", error);
1622 } catch (NoSuchArgument const& ex) {
1623 error = "unknown error";
1624 }
1626 }
1627 }
1628
1629 return (ConstElementPtr());
1630}
1631
1635
1636 if (!srv) {
1638 "Server object not initialized, can't process config.");
1639 return (no_srv);
1640 }
1641
1643 .arg(srv->redactConfig(config)->str());
1644
1645 return (configureDhcp4Server(*srv, config, true));
1646}
1647
1648ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
1649 uint16_t client_port /*= 0*/)
1650 : Dhcpv4Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1651 if (getInstance()) {
1653 "There is another Dhcpv4Srv instance already.");
1654 }
1655 server_ = this; // remember this instance for later use in handlers
1656
1657 // ProcessSpawn uses IO service to handle signal set events.
1659
1660 // TimerMgr uses IO service to run asynchronous timers.
1661 TimerMgr::instance()->setIOService(getIOService());
1662
1663 // Command managers use IO service to run asynchronous socket operations.
1666
1667 // Set the HTTP authentication default realm.
1669
1670 // Set the HTTP supported service.
1672
1673 // DatabaseConnection uses IO service to run asynchronous timers.
1675
1676 // These are the commands always supported by the DHCPv4 server.
1677 // Please keep the list in alphabetic order.
1678 CommandMgr::instance().registerCommand("build-report",
1679 std::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1680
1681 CommandMgr::instance().registerCommand("config-backend-pull",
1682 std::bind(&ControlledDhcpv4Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1683
1685 std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1686
1687 CommandMgr::instance().registerCommand("config-hash-get",
1688 std::bind(&ControlledDhcpv4Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1689
1690 CommandMgr::instance().registerCommand("config-reload",
1691 std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1692
1694 std::bind(&ControlledDhcpv4Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1695
1696 CommandMgr::instance().registerCommand("config-test",
1697 std::bind(&ControlledDhcpv4Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1698
1699 CommandMgr::instance().registerCommand("config-write",
1700 std::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1701
1702 CommandMgr::instance().registerCommand("dhcp-enable",
1703 std::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1704
1705 CommandMgr::instance().registerCommand("dhcp-disable",
1706 std::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1707
1708 CommandMgr::instance().registerCommand("interface-add",
1709 std::bind(&ControlledDhcpv4Srv::commandInterfaceAddHandler, this, ph::_1, ph::_2));
1710
1711 CommandMgr::instance().registerCommand("interface-list",
1712 std::bind(&ControlledDhcpv4Srv::commandInterfaceListHandler, this, ph::_1, ph::_2));
1713
1714 CommandMgr::instance().registerCommand("interface-redetect",
1715 std::bind(&ControlledDhcpv4Srv::commandInterfaceRedetectHandler, this, ph::_1, ph::_2));
1716
1717 CommandMgr::instance().registerCommand("kea-lfc-start",
1718 std::bind(&ControlledDhcpv4Srv::commandLfcStartHandler, this, ph::_1, ph::_2));
1719
1720 CommandMgr::instance().registerCommand("leases-reclaim",
1721 std::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1722
1723 CommandMgr::instance().registerCommand("subnet4-select-test",
1724 std::bind(&ControlledDhcpv4Srv::commandSubnet4SelectTestHandler, this, ph::_1, ph::_2));
1725
1726 CommandMgr::instance().registerCommand("subnet4o6-select-test",
1727 std::bind(&ControlledDhcpv4Srv::commandSubnet4o6SelectTestHandler, this, ph::_1, ph::_2));
1728
1729 CommandMgr::instance().registerCommand("server-tag-get",
1730 std::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1731
1733 std::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1734
1736 std::bind(&ControlledDhcpv4Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1737
1738 CommandMgr::instance().registerCommand("version-get",
1739 std::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1740
1741 // Register statistic related commands
1742 CommandMgr::instance().registerCommand("statistic-get",
1743 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1744
1745 CommandMgr::instance().registerCommand("statistic-reset",
1746 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1747
1748 CommandMgr::instance().registerCommand("statistic-remove",
1749 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1750
1751 CommandMgr::instance().registerCommand("statistic-get-all",
1752 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1753
1754 CommandMgr::instance().registerCommand("statistic-global-get-all",
1755 std::bind(&StatsMgr::statisticGlobalGetAllHandler, ph::_1, ph::_2));
1756
1757 CommandMgr::instance().registerCommand("statistic-reset-all",
1758 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1759
1760 CommandMgr::instance().registerCommand("statistic-remove-all",
1761 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1762
1763 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1764 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1765
1766 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1767 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1768
1769 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1770 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1771
1772 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1774}
1775
1777 setExitValue(exit_value);
1778 getIOService()->stop(); // Stop ASIO transmissions
1779 shutdown(); // Initiate DHCPv4 shutdown procedure.
1780}
1781
1783 try {
1784 MultiThreadingMgr::instance().apply(false, 0, 0);
1787
1788 // The closure captures either a shared pointer (memory leak)
1789 // or a raw pointer (pointing to a deleted object).
1793
1794 timer_mgr_->unregisterTimers();
1795
1796 cleanup();
1797
1798 // Close command sockets.
1801
1802 // Deregister any registered commands (please keep in alphabetic order)
1803 CommandMgr::instance().deregisterCommand("build-report");
1804 CommandMgr::instance().deregisterCommand("config-backend-pull");
1806 CommandMgr::instance().deregisterCommand("config-hash-get");
1807 CommandMgr::instance().deregisterCommand("config-reload");
1809 CommandMgr::instance().deregisterCommand("config-test");
1810 CommandMgr::instance().deregisterCommand("config-write");
1811 CommandMgr::instance().deregisterCommand("dhcp-disable");
1812 CommandMgr::instance().deregisterCommand("dhcp-enable");
1813 CommandMgr::instance().deregisterCommand("interface-add");
1814 CommandMgr::instance().deregisterCommand("interface-list");
1815 CommandMgr::instance().deregisterCommand("interface-redetect");
1816 CommandMgr::instance().deregisterCommand("kea-lfc-start");
1817 CommandMgr::instance().deregisterCommand("leases-reclaim");
1818 CommandMgr::instance().deregisterCommand("subnet4-select-test");
1819 CommandMgr::instance().deregisterCommand("subnet4o6-select-test");
1820 CommandMgr::instance().deregisterCommand("server-tag-get");
1822 CommandMgr::instance().deregisterCommand("statistic-get");
1823 CommandMgr::instance().deregisterCommand("statistic-get-all");
1824 CommandMgr::instance().deregisterCommand("statistic-global-get-all");
1825 CommandMgr::instance().deregisterCommand("statistic-remove");
1826 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1827 CommandMgr::instance().deregisterCommand("statistic-reset");
1828 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1829 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1830 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1831 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1832 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1834 CommandMgr::instance().deregisterCommand("version-get");
1835
1836 // Reset DatabaseConnection IO service.
1838 } catch (...) {
1839 // Don't want to throw exceptions from the destructor. The server
1840 // is shutting down anyway.
1841 }
1842
1843 server_ = NULL; // forget this instance. There should be no callback anymore
1844 // at this stage anyway.
1845}
1846
1847void
1848ControlledDhcpv4Srv::reclaimExpiredLeases(const size_t max_leases,
1849 const uint16_t timeout,
1850 const bool remove_lease,
1851 const uint16_t max_unwarned_cycles) {
1852 try {
1853 if (network_state_->isServiceEnabled()) {
1854 server_->alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
1855 remove_lease,
1856 max_unwarned_cycles);
1857 } else {
1859 .arg(CfgMgr::instance().getCurrentCfg()->
1860 getCfgExpiration()->getReclaimTimerWaitTime());
1861 }
1862 } catch (const std::exception& ex) {
1864 .arg(ex.what());
1865 }
1866 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1868}
1869
1870void
1871ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1872 if (network_state_->isServiceEnabled()) {
1873 server_->alloc_engine_->deleteExpiredReclaimedLeases4(secs);
1874 }
1875
1876 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1878}
1879
1880bool
1881ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1882 if (!db_reconnect_ctl) {
1883 // This should never happen
1885 return (false);
1886 }
1887
1888 // Disable service until the connection is recovered.
1889 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1890 db_reconnect_ctl->alterServiceState()) {
1891 network_state_->disableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1892 }
1893
1895 .arg(db_reconnect_ctl->id())
1896 .arg(db_reconnect_ctl->timerName());;
1897
1898 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1899 // return false.
1900 if (!db_reconnect_ctl->retriesLeft() ||
1901 !db_reconnect_ctl->retryInterval()) {
1902 if (db_reconnect_ctl->exitOnFailure()) {
1904 .arg(db_reconnect_ctl->retriesLeft())
1905 .arg(db_reconnect_ctl->retryInterval())
1906 .arg(db_reconnect_ctl->id())
1907 .arg(db_reconnect_ctl->timerName());
1908 shutdownServer(EXIT_FAILURE);
1909 } else {
1911 .arg(db_reconnect_ctl->retriesLeft())
1912 .arg(db_reconnect_ctl->retryInterval())
1913 .arg(db_reconnect_ctl->id())
1914 .arg(db_reconnect_ctl->timerName());
1915 }
1916 return (false);
1917 }
1918
1919 return (true);
1920}
1921
1922bool
1923ControlledDhcpv4Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1924 if (!db_reconnect_ctl) {
1925 // This should never happen
1927 return (false);
1928 }
1929
1930 // Enable service after the connection is recovered.
1931 if (db_reconnect_ctl->retriesLeft() != db_reconnect_ctl->maxRetries() &&
1932 db_reconnect_ctl->alterServiceState()) {
1933 network_state_->enableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1934 }
1935
1937 .arg(db_reconnect_ctl->id())
1938 .arg(db_reconnect_ctl->timerName());
1939
1940 db_reconnect_ctl->resetRetries();
1941
1942 return (true);
1943}
1944
1945bool
1946ControlledDhcpv4Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1947 if (!db_reconnect_ctl) {
1948 // This should never happen
1950 return (false);
1951 }
1952
1953 if (db_reconnect_ctl->exitOnFailure()) {
1955 .arg(db_reconnect_ctl->maxRetries())
1956 .arg(db_reconnect_ctl->id())
1957 .arg(db_reconnect_ctl->timerName());
1958 shutdownServer(EXIT_FAILURE);
1959 } else {
1961 .arg(db_reconnect_ctl->maxRetries())
1962 .arg(db_reconnect_ctl->id())
1963 .arg(db_reconnect_ctl->timerName());
1964 }
1965
1966 return (true);
1967}
1968
1969void
1970ControlledDhcpv4Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1971 if (!reconnect_ctl) {
1972 // This should never happen
1974 return;
1975 }
1976
1977 if (reconnect_ctl->exitOnFailure()) {
1979 .arg(reconnect_ctl->maxRetries());
1980 shutdownServer(EXIT_FAILURE);
1981 } else {
1983 .arg(reconnect_ctl->maxRetries());
1984 }
1985}
1986
1987void
1988ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1989 boost::shared_ptr<unsigned> failure_count) {
1990 // stop thread pool (if running)
1991 MultiThreadingCriticalSection cs;
1992
1993 try {
1994 // Fetch any configuration backend updates since our last fetch.
1995 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1996 CBControlDHCPv4::FetchMode::FETCH_UPDATE);
1997 (*failure_count) = 0;
1998
1999 } catch (const std::exception& ex) {
2001 .arg(ex.what());
2002
2003 // We allow at most 10 consecutive failures after which we stop
2004 // making further attempts to fetch the configuration updates.
2005 // Let's return without re-scheduling the timer.
2006 if (++(*failure_count) > 10) {
2009 return;
2010 }
2011 }
2012
2013 // Reschedule the timer to fetch new updates or re-try if
2014 // the previous attempt resulted in an error.
2015 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
2016 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
2017 }
2018}
2019
2020} // namespace dhcp
2021} // 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 an unrecoverable error occurs.
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:300
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:355
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:350
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:161
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)
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:678
void shutdown() override
Instructs the server to shut down.
Definition dhcp4_srv.cc:785
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:108
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:270
isc::asiolink::IOSignalSetPtr signal_set_
A pointer to the object installing custom signal handlers.
Definition daemon.h:286
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition daemon.h:292
void checkWriteConfigFile(std::string &file)
Checks the to-be-written configuration file name.
Definition daemon.cc:133
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:298
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:126
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
const isc::log::MessageID DHCP4_FATAL_DB_RECONNECT_FAILED
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_FATAL_DYNAMIC_RECONFIGURATION_FAIL
const isc::log::MessageID DHCP4_DB_RECONNECT_FAILED
const isc::log::MessageID DHCP4_OPEN_SOCKETS_FAILED
const isc::log::MessageID DHCP4_FATAL_DB_RECONNECT_DISABLED
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.