Kea 3.1.7
ctrl_dhcp4_srv.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2025 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>
31#include <hooks/hooks.h>
32#include <hooks/hooks_manager.h>
34#include <stats/stats_mgr.h>
35#include <util/encode/encode.h>
37
38#include <signal.h>
39
40#include <sstream>
41
42using namespace isc::asiolink;
43using namespace isc::config;
44using namespace isc::data;
45using namespace isc::db;
46using namespace isc::dhcp;
47using namespace isc::hooks;
48using namespace isc::stats;
49using namespace isc::util;
50using namespace std;
51namespace ph = std::placeholders;
52
53namespace {
54
56struct CtrlDhcp4Hooks {
57 int hooks_index_dhcp4_srv_configured_;
58
60 CtrlDhcp4Hooks() {
61 hooks_index_dhcp4_srv_configured_ = HooksManager::registerHook("dhcp4_srv_configured");
62 }
63
64};
65
66// Declare a Hooks object. As this is outside any function or method, it
67// will be instantiated (and the constructor run) when the module is loaded.
68// As a result, the hook indexes will be defined before any method in this
69// module is called.
70CtrlDhcp4Hooks Hooks;
71
81void signalHandler(int signo) {
82 // SIGHUP signals a request to reconfigure the server.
83 if (signo == SIGHUP) {
85 } else if ((signo == SIGTERM) || (signo == SIGINT)) {
87 }
88}
89
90}
91
92namespace isc {
93namespace dhcp {
94
95ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = NULL;
96
97void
98ControlledDhcpv4Srv::init(const std::string& file_name) {
99 // Keep the call timestamp.
100 start_ = boost::posix_time::second_clock::universal_time();
101
102 // Configure the server using JSON file.
103 ConstElementPtr result = loadConfigFile(file_name);
104
105 int rcode;
106 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
107 if (rcode != CONTROL_RESULT_SUCCESS) {
108 string reason = comment ? comment->stringValue() :
109 "no details available";
110 isc_throw(isc::BadValue, reason);
111 }
112
113 // Set signal handlers. When the SIGHUP is received by the process
114 // the server reconfiguration will be triggered. When SIGTERM or
115 // SIGINT will be received, the server will start shutting down.
116 signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
117
118 signal_set_->add(SIGINT);
119 signal_set_->add(SIGHUP);
120 signal_set_->add(SIGTERM);
121}
122
124 signal_set_.reset();
125 getIOService()->poll();
126}
127
129ControlledDhcpv4Srv::loadConfigFile(const std::string& file_name) {
130 // This is a configuration backend implementation that reads the
131 // configuration from a JSON file.
132
135
136 // Basic sanity check: file name must not be empty.
137 try {
138 if (file_name.empty()) {
139 // Basic sanity check: file name must not be empty.
140 isc_throw(isc::BadValue, "JSON configuration file not specified."
141 " Please use -c command line option.");
142 }
143
144 // Read contents of the file and parse it as JSON
145 Parser4Context parser;
146 json = parser.parseFile(file_name, Parser4Context::PARSER_DHCP4);
147 if (!json) {
148 isc_throw(isc::BadValue, "no configuration found");
149 }
150
151 // Let's do sanity check before we call json->get() which
152 // works only for map.
153 if (json->getType() != isc::data::Element::map) {
154 isc_throw(isc::BadValue, "Configuration file is expected to be "
155 "a map, i.e., start with { and end with } and contain "
156 "at least an entry called 'Dhcp4' that itself is a map. "
157 << file_name
158 << " is a valid JSON, but its top element is not a map."
159 " Did you forget to add { } around your configuration?");
160 }
161
162 // Use parsed JSON structures to configure the server
163 result = CommandMgr::instance().processCommand(createCommand("config-set", json));
164 if (!result) {
165 // Undetermined status of the configuration. This should never
166 // happen, but as the configureDhcp4Server returns a pointer, it is
167 // theoretically possible that it will return NULL.
168 isc_throw(isc::BadValue, "undefined result of "
169 "process command \"config-set\"");
170 }
171
172 // Now check is the returned result is successful (rcode=0) or not
173 // (see @ref isc::config::parseAnswer).
174 int rcode;
175 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
176 if (rcode != CONTROL_RESULT_SUCCESS) {
177 string reason = comment ? comment->stringValue() :
178 "no details available";
179 isc_throw(isc::BadValue, reason);
180 }
181 } catch (const std::exception& ex) {
182 // If configuration failed at any stage, we drop the staging
183 // configuration and continue to use the previous one.
185
187 .arg(file_name).arg(ex.what());
188 isc_throw(isc::BadValue, "configuration error using file '"
189 << file_name << "': " << ex.what());
190 }
191
193 .arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
194 .arg(MultiThreadingMgr::instance().getThreadPoolSize())
195 .arg(MultiThreadingMgr::instance().getPacketQueueSize());
196
197 return (result);
198}
199
201ControlledDhcpv4Srv::commandShutdownHandler(const string&, ConstElementPtr args) {
204 return (createAnswer(CONTROL_RESULT_ERROR, "Shutdown failure."));
205 }
206
207 int exit_value = 0;
208 if (args) {
209 // @todo Should we go ahead and shutdown even if the args are invalid?
210 if (args->getType() != Element::map) {
211 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
212 }
213
214 ConstElementPtr param = args->get("exit-value");
215 if (param) {
216 if (param->getType() != Element::integer) {
218 "parameter 'exit-value' is not an integer"));
219 }
220
221 exit_value = param->intValue();
222 }
223 }
224
226 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
227}
228
230ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
231 ConstElementPtr /*args*/) {
232 // Get configuration file name.
234 try {
236 auto result = loadConfigFile(file);
238 return (result);
239 } catch (const std::exception& ex) {
240 // Log the unsuccessful reconfiguration. The reason for failure
241 // should be already logged. Don't rethrow an exception so as
242 // the server keeps working.
244 .arg(file);
246 "Config reload failed: " + string(ex.what())));
247 }
248}
249
251ControlledDhcpv4Srv::commandConfigGetHandler(const string&,
252 ConstElementPtr /*args*/) {
253 ElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
254 string hash = BaseCommandMgr::getHash(config);
255 config->set("hash", Element::create(hash));
256
257 return (createAnswer(CONTROL_RESULT_SUCCESS, config));
258}
259
261ControlledDhcpv4Srv::commandConfigHashGetHandler(const string&,
262 ConstElementPtr /*args*/) {
263 ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
264
265 string hash = BaseCommandMgr::getHash(config);
266
268 params->set("hash", Element::create(hash));
269 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
270}
271
273ControlledDhcpv4Srv::commandConfigWriteHandler(const string&,
274 ConstElementPtr args) {
275 string filename;
276
277 if (args) {
278 if (args->getType() != Element::map) {
279 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
280 }
281 ConstElementPtr filename_param = args->get("filename");
282 if (filename_param) {
283 if (filename_param->getType() != Element::string) {
285 "passed parameter 'filename' is not a string"));
286 }
287 filename = filename_param->stringValue();
288 }
289 }
290
291 if (filename.empty()) {
292 // filename parameter was not specified, so let's use whatever we remember
293 // from the command-line
294 filename = getConfigFile();
295 if (filename.empty()) {
296 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
297 "Please specify filename explicitly."));
298 }
299 } else {
300 try {
301 checkWriteConfigFile(filename);
302 } catch (const isc::Exception& ex) {
303 std::ostringstream msg;
304 msg << "not allowed to write config into " << filename
305 << ": " << ex.what();
306 return (createAnswer(CONTROL_RESULT_ERROR, msg.str()));
307 }
308 }
309
310 // Ok, it's time to write the file.
311 size_t size = 0;
312 try {
313 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
314 size = writeConfigFile(filename, cfg);
315 } catch (const isc::Exception& ex) {
316 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during config-write: ")
317 + ex.what()));
318 }
319 if (size == 0) {
320 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
321 + filename));
322 }
323
324 // Ok, it's time to return the successful response.
326 params->set("size", Element::create(static_cast<long long>(size)));
327 params->set("filename", Element::create(filename));
328
329 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
330 + filename + " successful", params));
331}
332
334ControlledDhcpv4Srv::commandConfigSetHandler(const string&,
335 ConstElementPtr args) {
336 const int status_code = CONTROL_RESULT_ERROR;
337 ConstElementPtr dhcp4;
338 string message;
339
340 // Command arguments are expected to be:
341 // { "Dhcp4": { ... } }
342 if (!args) {
343 message = "Missing mandatory 'arguments' parameter.";
344 } else {
345 dhcp4 = args->get("Dhcp4");
346 if (!dhcp4) {
347 message = "Missing mandatory 'Dhcp4' parameter.";
348 } else if (dhcp4->getType() != Element::map) {
349 message = "'Dhcp4' parameter expected to be a map.";
350 }
351 }
352
353 // Check unsupported objects.
354 if (message.empty()) {
355 for (auto const& obj : args->mapValue()) {
356 const string& obj_name = obj.first;
357 if (obj_name != "Dhcp4") {
359 .arg(obj_name);
360 if (message.empty()) {
361 message = "Unsupported '" + obj_name + "' parameter";
362 } else {
363 message += " (and '" + obj_name + "')";
364 }
365 }
366 }
367 if (!message.empty()) {
368 message += ".";
369 }
370 }
371
372 if (!message.empty()) {
373 // Something is amiss with arguments, return a failure response.
374 ConstElementPtr result = isc::config::createAnswer(status_code,
375 message);
376 return (result);
377 }
378
380 (LeaseMgrFactory::instance().getType() == "memfile")) {
381 Memfile_LeaseMgr& mgr = dynamic_cast<Memfile_LeaseMgr&>(LeaseMgrFactory::instance());
382 auto file_name = mgr.getLeaseFilePath(Memfile_LeaseMgr::V4);
385 "Can not update configuration while lease file cleanup process is running."));
386 }
387 }
388
389 // stop thread pool (if running)
390 MultiThreadingCriticalSection cs;
391
392 // We are starting the configuration process so we should remove any
393 // staging configuration that has been created during previous
394 // configuration attempts.
396
397 // Parse the logger configuration explicitly into the staging config.
398 // Note this does not alter the current loggers, they remain in
399 // effect until we apply the logging config below. If no logging
400 // is supplied logging will revert to default logging.
401 Daemon::configureLogger(dhcp4, CfgMgr::instance().getStagingCfg());
402
403 // Let's apply the new logging. We do it early, so we'll be able to print
404 // out what exactly is wrong with the new config in case of problems.
405 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
406
407 // Now we configure the server proper.
408 ConstElementPtr result = processConfig(dhcp4);
409
410 // If the configuration parsed successfully, apply the new logger
411 // configuration and then commit the new configuration. We apply
412 // the logging first in case there's a configuration failure.
413 int rcode = 0;
414 isc::config::parseAnswer(rcode, result);
415 if (rcode == CONTROL_RESULT_SUCCESS) {
416 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
417
418 // Use new configuration.
420 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
421 // Ok, we applied the logging from the upcoming configuration, but
422 // there were problems with the config. As such, we need to back off
423 // and revert to the previous logging configuration. This is not done if
424 // sequence == 0, because that would mean always reverting to stdout by
425 // default, and it is arguably more helpful to have the error in a
426 // potential file or syslog configured in the upcoming configuration.
427 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
428
429 // Not initial configuration so someone can believe we reverted
430 // to the previous configuration. It is not the case so be clear
431 // about this.
433 }
434
436 try {
437 // Handle events registered by hooks using external IOService objects.
439 } catch (const std::exception& ex) {
440 std::ostringstream err;
441 err << "Error initializing hooks: "
442 << ex.what();
444 }
445
446 return (result);
447}
448
450ControlledDhcpv4Srv::commandConfigTestHandler(const string&,
451 ConstElementPtr args) {
452 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
453 ConstElementPtr dhcp4;
454 string message;
455
456 // Command arguments are expected to be:
457 // { "Dhcp4": { ... } }
458 if (!args) {
459 message = "Missing mandatory 'arguments' parameter.";
460 } else {
461 dhcp4 = args->get("Dhcp4");
462 if (!dhcp4) {
463 message = "Missing mandatory 'Dhcp4' parameter.";
464 } else if (dhcp4->getType() != Element::map) {
465 message = "'Dhcp4' parameter expected to be a map.";
466 }
467 }
468
469 // Check unsupported objects.
470 if (message.empty()) {
471 for (auto const& obj : args->mapValue()) {
472 const string& obj_name = obj.first;
473 if (obj_name != "Dhcp4") {
475 .arg(obj_name);
476 if (message.empty()) {
477 message = "Unsupported '" + obj_name + "' parameter";
478 } else {
479 message += " (and '" + obj_name + "')";
480 }
481 }
482 }
483 if (!message.empty()) {
484 message += ".";
485 }
486 }
487
488 if (!message.empty()) {
489 // Something is amiss with arguments, return a failure response.
490 ConstElementPtr result = isc::config::createAnswer(status_code,
491 message);
492 return (result);
493 }
494
495 // stop thread pool (if running)
496 MultiThreadingCriticalSection cs;
497
498 // We are starting the configuration process so we should remove any
499 // staging configuration that has been created during previous
500 // configuration attempts.
502
503 // Now we check the server proper.
504 return (checkConfig(dhcp4));
505}
506
508ControlledDhcpv4Srv::commandDhcpDisableHandler(const std::string&,
509 ConstElementPtr args) {
510 std::ostringstream message;
511 int64_t max_period = 0;
512 std::string origin;
513
514 // If the args map does not contain 'origin' parameter, the default type
515 // will be used (user command).
516 auto type = NetworkState::USER_COMMAND;
517
518 // Parse arguments to see if the 'max-period' or 'origin' parameters have
519 // been specified.
520 if (args) {
521 // Arguments must be a map.
522 if (args->getType() != Element::map) {
523 message << "arguments for the 'dhcp-disable' command must be a map";
524
525 } else {
526 ConstElementPtr max_period_element = args->get("max-period");
527 // max-period is optional.
528 if (max_period_element) {
529 // It must be an integer, if specified.
530 if (max_period_element->getType() != Element::integer) {
531 message << "'max-period' argument must be a number";
532
533 } else {
534 // It must be positive integer.
535 max_period = max_period_element->intValue();
536 if (max_period <= 0) {
537 message << "'max-period' must be positive integer";
538 }
539 }
540 }
541 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
542 // stable release. However, the 'origin' is kept for backward compatibility
543 // with Kea versions before 2.5.8. It is common to receive both parameters
544 // because HA hook library sends both in case the partner server hasn't been
545 // upgraded to the new version. The 'origin-id' takes precedence over the
546 // 'origin'.
547 ConstElementPtr origin_id_element = args->get("origin-id");
548 ConstElementPtr origin_element = args->get("origin");
549 // The 'origin-id' and 'origin' arguments are optional.
550 if (origin_id_element) {
551 if (origin_id_element->getType() == Element::integer) {
552 type = origin_id_element->intValue();
553 } else {
554 message << "'origin-id' argument must be a number";
555 }
556 } else if (origin_element) {
557 switch (origin_element->getType()) {
558 case Element::string:
559 origin = origin_element->stringValue();
560 if (origin == "ha-partner") {
562 } else if (origin != "user") {
563 if (origin.empty()) {
564 origin = "(empty string)";
565 }
566 message << "invalid value used for 'origin' parameter: "
567 << origin;
568 }
569 break;
570 case Element::integer:
571 type = origin_element->intValue();
572 break;
573 default:
574 // It must be a string or a number, if specified.
575 message << "'origin' argument must be a string or a number";
576 }
577 }
578 }
579 }
580
581 // No error occurred, so let's disable the service.
582 if (message.tellp() == 0) {
583 message << "DHCPv4 service disabled";
584 if (max_period > 0) {
585 message << " for " << max_period << " seconds";
586
587 // The user specified that the DHCP service should resume not
588 // later than in max-period seconds. If the 'dhcp-enable' command
589 // is not sent, the DHCP service will resume automatically.
590 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
591 type);
592 }
593 network_state_->disableService(type);
594
595 // Success.
596 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
597 }
598
599 // Failure.
600 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
601}
602
604ControlledDhcpv4Srv::commandDhcpEnableHandler(const std::string&,
605 ConstElementPtr args) {
606 std::ostringstream message;
607 std::string origin;
608
609 // If the args map does not contain 'origin' parameter, the default type
610 // will be used (user command).
611 auto type = NetworkState::USER_COMMAND;
612
613 // Parse arguments to see if the 'origin' parameter has been specified.
614 if (args) {
615 // Arguments must be a map.
616 if (args->getType() != Element::map) {
617 message << "arguments for the 'dhcp-enable' command must be a map";
618
619 } else {
620 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
621 // stable release. However, the 'origin' is kept for backward compatibility
622 // with Kea versions before 2.5.8. It is common to receive both parameters
623 // because HA hook library sends both in case the partner server hasn't been
624 // upgraded to the new version. The 'origin-id' takes precedence over the
625 // 'origin'.
626 ConstElementPtr origin_id_element = args->get("origin-id");
627 ConstElementPtr origin_element = args->get("origin");
628 // The 'origin-id' and 'origin' arguments are optional.
629 if (origin_id_element) {
630 if (origin_id_element->getType() == Element::integer) {
631 type = origin_id_element->intValue();
632 } else {
633 message << "'origin-id' argument must be a number";
634 }
635 } else if (origin_element) {
636 switch (origin_element->getType()) {
637 case Element::string:
638 origin = origin_element->stringValue();
639 if (origin == "ha-partner") {
641 } else if (origin != "user") {
642 if (origin.empty()) {
643 origin = "(empty string)";
644 }
645 message << "invalid value used for 'origin' parameter: "
646 << origin;
647 }
648 break;
649 case Element::integer:
650 type = origin_element->intValue();
651 break;
652 default:
653 // It must be a string or a number, if specified.
654 message << "'origin' argument must be a string or a number";
655 }
656 }
657 }
658 }
659
660 // No error occurred, so let's enable the service.
661 if (message.tellp() == 0) {
662 network_state_->enableService(type);
663
664 // Success.
666 "DHCP service successfully enabled"));
667 }
668
669 // Failure.
670 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
671}
672
674ControlledDhcpv4Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
676 ElementPtr arguments = Element::createMap();
677 arguments->set("extended", extended);
680 arguments);
681 return (answer);
682}
683
685ControlledDhcpv4Srv::commandBuildReportHandler(const string&,
687 ConstElementPtr answer =
689 return (answer);
690}
691
693ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
694 ConstElementPtr args) {
695 int status_code = CONTROL_RESULT_ERROR;
696 string message;
697
698 // args must be { "remove": <bool> }
699 if (!args) {
700 message = "Missing mandatory 'remove' parameter.";
701 } else {
702 ConstElementPtr remove_name = args->get("remove");
703 if (!remove_name) {
704 message = "Missing mandatory 'remove' parameter.";
705 } else if (remove_name->getType() != Element::boolean) {
706 message = "'remove' parameter expected to be a boolean.";
707 } else {
708 bool remove_lease = remove_name->boolValue();
709 server_->alloc_engine_->reclaimExpiredLeases4(0, 0, remove_lease);
710 status_code = 0;
711 message = "Reclamation of expired leases is complete.";
712 }
713 }
714 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
715 return (answer);
716}
717
719ControlledDhcpv4Srv::commandSubnet4SelectTestHandler(const string&,
720 ConstElementPtr args) {
721 if (!args) {
722 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
723 }
724 if (args->getType() != Element::map) {
725 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
726 }
727 bool ignore_link_sel =
728 CfgMgr::instance().getCurrentCfg()->getIgnoreRAILinkSelection();
729 SubnetSelector selector;
730 for (auto const& entry : args->mapValue()) {
731 ostringstream errmsg;
732 if (entry.first == "interface") {
733 if (entry.second->getType() != Element::string) {
734 errmsg << "'interface' entry must be a string";
735 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
736 }
737 selector.iface_name_ = entry.second->stringValue();
738 continue;
739 } else if (entry.first == "address") {
740 if (entry.second->getType() != Element::string) {
741 errmsg << "'address' entry must be a string";
742 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
743 }
744 try {
745 IOAddress addr(entry.second->stringValue());
746 if (!addr.isV4()) {
747 errmsg << "bad 'address' entry: not IPv4";
748 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
749 }
750 selector.ciaddr_ = addr;
751 continue;
752 } catch (const exception& ex) {
753 errmsg << "bad 'address' entry: " << ex.what();
754 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
755 }
756 } else if (entry.first == "relay") {
757 if (entry.second->getType() != Element::string) {
758 errmsg << "'relay' entry must be a string";
759 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
760 }
761 try {
762 IOAddress addr(entry.second->stringValue());
763 if (!addr.isV4()) {
764 errmsg << "bad 'relay' entry: not IPv4";
765 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
766 }
767 selector.giaddr_ = addr;
768 continue;
769 } catch (const exception& ex) {
770 errmsg << "bad 'relay' entry: " << ex.what();
771 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
772 }
773 } else if (entry.first == "local") {
774 if (entry.second->getType() != Element::string) {
775 errmsg << "'local' entry must be a string";
776 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
777 }
778 try {
779 IOAddress addr(entry.second->stringValue());
780 if (!addr.isV4()) {
781 errmsg << "bad 'local' entry: not IPv4";
782 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
783 }
784 selector.local_address_ = addr;
785 continue;
786 } catch (const exception& ex) {
787 errmsg << "bad 'local' entry: " << ex.what();
788 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
789 }
790 } else if (entry.first == "remote") {
791 if (entry.second->getType() != Element::string) {
792 errmsg << "'remote' entry must be a string";
793 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
794 }
795 try {
796 IOAddress addr(entry.second->stringValue());
797 if (!addr.isV4()) {
798 errmsg << "bad 'remote' entry: not IPv4";
799 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
800 }
801 selector.remote_address_ = addr;
802 continue;
803 } catch (const exception& ex) {
804 errmsg << "bad 'remote' entry: " << ex.what();
805 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
806 }
807 } else if (entry.first == "link") {
808 if (entry.second->getType() != Element::string) {
809 errmsg << "'link' entry must be a string";
810 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
811 }
812 try {
813 IOAddress addr(entry.second->stringValue());
814 if (!addr.isV4()) {
815 errmsg << "bad 'link' entry: not IPv4";
816 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
817 }
818 if (!ignore_link_sel) {
819 selector.option_select_ = addr;
820 }
821 continue;
822 } catch (const exception& ex) {
823 errmsg << "bad 'link' entry: " << ex.what();
824 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
825 }
826 } else if (entry.first == "subnet") {
827 // RAI link-selection has precedence over subnet-selection.
828 if (args->contains("link") && !ignore_link_sel) {
829 continue;
830 }
831 if (entry.second->getType() != Element::string) {
832 errmsg << "'subnet' entry must be a string";
833 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
834 }
835 try {
836 IOAddress addr(entry.second->stringValue());
837 if (!addr.isV4()) {
838 errmsg << "bad 'subnet' entry: not IPv4";
839 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
840 }
841 selector.option_select_ = addr;
842 continue;
843 } catch (const exception& ex) {
844 errmsg << "bad 'subnet' entry: " << ex.what();
845 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
846 }
847 } else if (entry.first == "classes") {
848 if (entry.second->getType() != Element::list) {
850 "'classes' entry must be a list"));
851 }
852 for (auto const& item : entry.second->listValue()) {
853 if (!item || (item->getType() != Element::string)) {
854 errmsg << "'classes' entry must be a list of strings";
855 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
856 }
857 // Skip empty client classes.
858 if (!item->stringValue().empty()) {
859 selector.client_classes_.insert(item->stringValue());
860 }
861 }
862 continue;
863 } else {
864 errmsg << "unknown entry '" << entry.first << "'";
865 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
866 }
867 }
869 getCfgSubnets4()->selectSubnet(selector);
870 if (!subnet) {
871 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
872 }
873 SharedNetwork4Ptr network;
874 subnet->getSharedNetwork(network);
875 ostringstream msg;
876 if (network) {
877 msg << "selected shared network '" << network->getName()
878 << "' starting with subnet '" << subnet->toText()
879 << "' id " << subnet->getID();
880 } else {
881 msg << "selected subnet '" << subnet->toText()
882 << "' id " << subnet->getID();
883 }
884 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
885}
886
888ControlledDhcpv4Srv::commandSubnet4o6SelectTestHandler(const string&,
889 ConstElementPtr args) {
890 if (!args) {
891 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
892 }
893 if (args->getType() != Element::map) {
894 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
895 }
896 SubnetSelector selector;
897 selector.dhcp4o6_ = true;
900 for (auto const& entry : args->mapValue()) {
901 ostringstream errmsg;
902 if (entry.first == "interface") {
903 if (entry.second->getType() != Element::string) {
904 errmsg << "'interface' entry must be a string";
905 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
906 }
907 selector.iface_name_ = entry.second->stringValue();
908 continue;
909 } if (entry.first == "interface-id") {
910 if (entry.second->getType() != Element::string) {
911 errmsg << "'interface-id' entry must be a string";
912 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
913 }
914 try {
915 string str = entry.second->stringValue();
916 vector<uint8_t> id = util::str::quotedStringToBinary(str);
917 if (id.empty()) {
919 }
920 if (id.empty()) {
921 errmsg << "'interface-id' must be not empty";
922 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
923 }
924 selector.interface_id_ = OptionPtr(new Option(Option::V6,
926 id));
927 continue;
928 } catch (...) {
929 errmsg << "value of 'interface-id' was not recognized";
930 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
931 }
932 } else if (entry.first == "address") {
933 if (entry.second->getType() != Element::string) {
934 errmsg << "'address' entry must be a string";
935 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
936 }
937 try {
938 IOAddress addr(entry.second->stringValue());
939 if (!addr.isV4()) {
940 errmsg << "bad 'address' entry: not IPv4";
941 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
942 }
943 selector.ciaddr_ = addr;
944 continue;
945 } catch (const exception& ex) {
946 errmsg << "bad 'address' entry: " << ex.what();
947 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
948 }
949 } else if (entry.first == "relay") {
950 if (entry.second->getType() != Element::string) {
951 errmsg << "'relay' entry must be a string";
952 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
953 }
954 try {
955 IOAddress addr(entry.second->stringValue());
956 if (!addr.isV4()) {
957 errmsg << "bad 'relay' entry: not IPv4";
958 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
959 }
960 selector.giaddr_ = addr;
961 continue;
962 } catch (const exception& ex) {
963 errmsg << "bad 'relay' entry: " << ex.what();
964 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
965 }
966 } else if (entry.first == "local") {
967 if (entry.second->getType() != Element::string) {
968 errmsg << "'local' entry must be a string";
969 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
970 }
971 try {
972 IOAddress addr(entry.second->stringValue());
973 if (!addr.isV6()) {
974 errmsg << "bad 'local' entry: not IPv6";
975 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
976 }
977 selector.local_address_ = addr;
978 continue;
979 } catch (const exception& ex) {
980 errmsg << "bad 'local' entry: " << ex.what();
981 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
982 }
983 } else if (entry.first == "remote") {
984 if (entry.second->getType() != Element::string) {
985 errmsg << "'remote' entry must be a string";
986 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
987 }
988 try {
989 IOAddress addr(entry.second->stringValue());
990 if (!addr.isV6()) {
991 errmsg << "bad 'remote' entry: not IPv6";
992 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
993 }
994 selector.remote_address_ = addr;
995 continue;
996 } catch (const exception& ex) {
997 errmsg << "bad 'remote' entry: " << ex.what();
998 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
999 }
1000 } else if (entry.first == "link") {
1001 if (entry.second->getType() != Element::string) {
1002 errmsg << "'link' entry must be a string";
1003 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1004 }
1005 try {
1006 IOAddress addr(entry.second->stringValue());
1007 if (!addr.isV6()) {
1008 errmsg << "bad 'link' entry: not IPv6";
1009 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1010 }
1011 selector.first_relay_linkaddr_ = addr;
1012 continue;
1013 } catch (const exception& ex) {
1014 errmsg << "bad 'link' entry: " << ex.what();
1015 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1016 }
1017 } else if (entry.first == "subnet") {
1018 if (entry.second->getType() != Element::string) {
1019 errmsg << "'subnet' entry must be a string";
1020 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1021 }
1022 try {
1023 IOAddress addr(entry.second->stringValue());
1024 if (!addr.isV4()) {
1025 errmsg << "bad 'subnet' entry: not IPv4";
1026 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1027 }
1028 selector.option_select_ = addr;
1029 continue;
1030 } catch (const exception& ex) {
1031 errmsg << "bad 'subnet' entry: " << ex.what();
1032 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1033 }
1034 } else if (entry.first == "classes") {
1035 if (entry.second->getType() != Element::list) {
1037 "'classes' entry must be a list"));
1038 }
1039 for (auto const& item : entry.second->listValue()) {
1040 if (!item || (item->getType() != Element::string)) {
1041 errmsg << "'classes' entry must be a list of strings";
1042 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1043 }
1044 // Skip empty client classes.
1045 if (!item->stringValue().empty()) {
1046 selector.client_classes_.insert(item->stringValue());
1047 }
1048 }
1049 continue;
1050 } else {
1051 errmsg << "unknown entry '" << entry.first << "'";
1052 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1053 }
1054 }
1056 getCfgSubnets4()->selectSubnet4o6(selector);
1057 if (!subnet) {
1058 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
1059 }
1060 SharedNetwork4Ptr network;
1061 subnet->getSharedNetwork(network);
1062 ostringstream msg;
1063 if (network) {
1064 msg << "selected shared network '" << network->getName()
1065 << "' starting with subnet '" << subnet->toText()
1066 << "' id " << subnet->getID();
1067 } else {
1068 msg << "selected subnet '" << subnet->toText()
1069 << "' id " << subnet->getID();
1070 }
1071 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
1072}
1073
1075ControlledDhcpv4Srv::commandServerTagGetHandler(const std::string&,
1077 const std::string& tag =
1078 CfgMgr::instance().getCurrentCfg()->getServerTag();
1079 ElementPtr response = Element::createMap();
1080 response->set("server-tag", Element::create(tag));
1081
1082 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
1083}
1084
1086ControlledDhcpv4Srv::commandConfigBackendPullHandler(const std::string&,
1088 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
1089 if (!ctl_info) {
1090 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
1091 }
1092
1093 // stop thread pool (if running)
1094 MultiThreadingCriticalSection cs;
1095
1096 // Reschedule the periodic CB fetch.
1097 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1098 TimerMgr::instance()->cancel("Dhcp4CBFetchTimer");
1099 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1100 }
1101
1102 // Code from cbFetchUpdates.
1103 // The configuration to use is the current one because this is called
1104 // after the configuration manager commit.
1105 try {
1106 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
1107 auto mode = CBControlDHCPv4::FetchMode::FETCH_UPDATE;
1108 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
1109 } catch (const std::exception& ex) {
1111 .arg(ex.what());
1113 "On demand configuration update failed: " +
1114 string(ex.what())));
1115 }
1117 "On demand configuration update successful."));
1118}
1119
1121ControlledDhcpv4Srv::commandStatusGetHandler(const string&,
1122 ConstElementPtr /*args*/) {
1123 ElementPtr status = Element::createMap();
1124 status->set("pid", Element::create(static_cast<int>(getpid())));
1125
1126 auto now = boost::posix_time::second_clock::universal_time();
1127 // Sanity check: start_ is always initialized.
1128 if (!start_.is_not_a_date_time()) {
1129 auto uptime = now - start_;
1130 status->set("uptime", Element::create(uptime.total_seconds()));
1131 }
1132
1133 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
1134 if (!last_commit.is_not_a_date_time()) {
1135 auto reload = now - last_commit;
1136 status->set("reload", Element::create(reload.total_seconds()));
1137 }
1138
1139 auto& mt_mgr = MultiThreadingMgr::instance();
1140 if (mt_mgr.getMode()) {
1141 status->set("multi-threading-enabled", Element::create(true));
1142 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
1143 MultiThreadingMgr::instance().getThreadPoolSize())));
1144 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
1145 MultiThreadingMgr::instance().getPacketQueueSize())));
1146 ElementPtr queue_stats = Element::createList();
1147 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
1148 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
1149 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
1150 status->set("packet-queue-statistics", queue_stats);
1151
1152 } else {
1153 status->set("multi-threading-enabled", Element::create(false));
1154 }
1155
1156 // Merge lease manager status.
1157 ElementPtr lm_info;
1160 }
1161 if (lm_info && (lm_info->getType() == Element::map)) {
1162 for (auto const& entry : lm_info->mapValue()) {
1163 status->set(entry.first, entry.second);
1164 }
1165 }
1166
1167 // Iterate through the interfaces and get all the errors.
1168 ElementPtr socket_errors(Element::createList());
1169 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
1170 for (std::string const& error : interface->getErrors()) {
1171 socket_errors->add(Element::create(error));
1172 }
1173 }
1174
1175 // Abstract the information from all sockets into a single status.
1176 ElementPtr sockets(Element::createMap());
1177 if (socket_errors->empty()) {
1178 sockets->set("status", Element::create("ready"));
1179 } else {
1180 ReconnectCtlPtr const reconnect_ctl(
1181 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
1182 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
1183 sockets->set("status", Element::create("retrying"));
1184 } else {
1185 sockets->set("status", Element::create("failed"));
1186 }
1187 sockets->set("errors", socket_errors);
1188 }
1189 status->set("sockets", sockets);
1190
1191 status->set("dhcp-state", network_state_->toElement());
1192
1193 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
1194}
1195
1197ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
1198 ConstElementPtr args) {
1199 StatsMgr& stats_mgr = StatsMgr::instance();
1201 // Update the default parameter.
1202 long max_samples = stats_mgr.getMaxSampleCountDefault();
1203 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1204 "statistic-default-sample-count", Element::create(max_samples));
1205 return (answer);
1206}
1207
1209ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
1210 ConstElementPtr args) {
1211 StatsMgr& stats_mgr = StatsMgr::instance();
1212 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleAgeAllHandler(args);
1213 // Update the default parameter.
1214 auto duration = stats_mgr.getMaxSampleAgeDefault();
1215 long max_age = toSeconds(duration);
1216 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1217 "statistic-default-sample-age", Element::create(max_age));
1218 return (answer);
1219}
1220
1222ControlledDhcpv4Srv::commandLfcStartHandler(const string&, ConstElementPtr) {
1224 return (LeaseMgrFactory::instance().lfcStartHandler());
1225 }
1227 "no lease backend"));
1228}
1229
1233
1234 // Allow DB reconnect on startup. The database connection parameters specify
1235 // respective details.
1237
1238 // Single stream instance used in all error clauses
1239 std::ostringstream err;
1240
1241 if (!srv) {
1242 err << "Server object not initialized, can't process config.";
1244 }
1245
1247 .arg(srv->redactConfig(config)->str());
1248
1249 // Destroy lease manager before hooks unload.
1251
1252 // Destroy host manager before hooks unload.
1254
1256
1257 // Check that configuration was successful. If not, do not reopen sockets
1258 // and don't bother with DDNS stuff.
1259 try {
1260 int rcode = 0;
1261 isc::config::parseAnswer(rcode, answer);
1262 if (rcode != 0) {
1263 return (answer);
1264 }
1265 } catch (const std::exception& ex) {
1266 err << "Failed to process configuration:" << ex.what();
1268 }
1269
1270 // Re-open lease and host database with new parameters.
1271 try {
1273 std::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, ph::_1);
1274
1276 std::bind(&ControlledDhcpv4Srv::dbRecoveredCallback, srv, ph::_1);
1277
1279 std::bind(&ControlledDhcpv4Srv::dbFailedCallback, srv, ph::_1);
1280
1281 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
1282 string params = "universe=4";
1283 cfg_db->setAppendedParameters(params);
1284 cfg_db->createManagers();
1285 // Reset counters related to connections as all managers have been recreated.
1286 srv->getNetworkState()->resetForDbConnection();
1287 srv->getNetworkState()->resetForLocalCommands();
1288 srv->getNetworkState()->resetForRemoteCommands();
1289 } catch (const std::exception& ex) {
1290 err << "Unable to open database: " << ex.what();
1292 }
1293
1294 // Server will start DDNS communications if its enabled.
1295 try {
1296 srv->startD2();
1297 } catch (const std::exception& ex) {
1298 err << "Error starting DHCP_DDNS client after server reconfiguration: "
1299 << ex.what();
1301 }
1302
1303 // Setup DHCPv4-over-DHCPv6 IPC
1304 try {
1306 } catch (const std::exception& ex) {
1307 err << "error starting DHCPv4-over-DHCPv6 IPC "
1308 " after server reconfiguration: " << ex.what();
1310 }
1311
1312 // Configure DHCP packet queueing
1313 try {
1315 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
1316 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
1318 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
1319 }
1320
1321 } catch (const std::exception& ex) {
1322 err << "Error setting packet queue controls after server reconfiguration: "
1323 << ex.what();
1325 }
1326
1327 // Configure a callback to shut down the server when the bind socket
1328 // attempts exceeded.
1330 std::bind(&ControlledDhcpv4Srv::openSocketsFailedCallback, srv, ph::_1);
1331
1332 // Configuration may change active interfaces. Therefore, we have to reopen
1333 // sockets according to new configuration. It is possible that this
1334 // operation will fail for some interfaces but the openSockets function
1335 // guards against exceptions and invokes a callback function to
1336 // log warnings. Since we allow that this fails for some interfaces there
1337 // is no need to rollback configuration if socket fails to open on any
1338 // of the interfaces.
1339 CfgMgr::instance().getStagingCfg()->getCfgIface()->
1340 openSockets(AF_INET, srv->getServerPort(),
1342
1343 // Install the timers for handling leases reclamation.
1344 try {
1345 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
1346 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
1347 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
1348 server_);
1349
1350 } catch (const std::exception& ex) {
1351 err << "unable to setup timers for periodically running the"
1352 " reclamation of the expired leases: "
1353 << ex.what() << ".";
1355 }
1356
1357 // Setup config backend polling, if configured for it.
1358 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
1359 if (ctl_info) {
1360 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
1361 // Only schedule the CB fetch timer if the fetch wait time is greater
1362 // than 0.
1363 if (fetch_time > 0) {
1364 // When we run unit tests, we want to use milliseconds unit for the
1365 // specified interval. Otherwise, we use seconds. Note that using
1366 // milliseconds as a unit in unit tests prevents us from waiting 1
1367 // second on more before the timer goes off. Instead, we wait one
1368 // millisecond which significantly reduces the test time.
1369 if (!server_->inTestMode()) {
1370 fetch_time = 1000 * fetch_time;
1371 }
1372
1373 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1375 registerTimer("Dhcp4CBFetchTimer",
1376 std::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
1377 server_, CfgMgr::instance().getStagingCfg(),
1378 failure_count),
1379 fetch_time,
1381 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1382 }
1383 }
1384
1385 // Finally, we can commit runtime option definitions in libdhcp++. This is
1386 // exception free.
1388
1390 if (notify_libraries) {
1391 return (notify_libraries);
1392 }
1393
1394 // Initialize the allocators. If the user selected a Free Lease Queue Allocator
1395 // for any of the subnets, the server will now populate free leases to the queue.
1396 // It may take a while!
1397 try {
1398 CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->initAllocatorsAfterConfigure();
1399
1400 } catch (const std::exception& ex) {
1401 err << "Error initializing the lease allocators: "
1402 << ex.what();
1404 }
1405
1406 // Apply multi threading settings.
1407 // @note These settings are applied/updated only if no errors occur while
1408 // applying the new configuration.
1409 // @todo This should be fixed.
1410 try {
1411 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1412 } catch (const std::exception& ex) {
1413 err << "Error applying multi threading settings: "
1414 << ex.what();
1416 }
1417
1418 return (answer);
1419}
1420
1424 // This hook point notifies hooks libraries that the configuration of the
1425 // DHCPv4 server has completed. It provides the hook library with the pointer
1426 // to the common IO service object, new server configuration in the JSON
1427 // format and with the pointer to the configuration storage where the
1428 // parsed configuration is stored.
1429 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp4_srv_configured_)) {
1431
1432 callout_handle->setArgument("io_context", srv->getIOService());
1433 callout_handle->setArgument("network_state", srv->getNetworkState());
1434 callout_handle->setArgument("json_config", config);
1435 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1436
1437 HooksManager::callCallouts(Hooks.hooks_index_dhcp4_srv_configured_,
1438 *callout_handle);
1439
1440 // If next step is DROP, report a configuration error.
1441 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1442 string error;
1443 try {
1444 callout_handle->getArgument("error", error);
1445 } catch (NoSuchArgument const& ex) {
1446 error = "unknown error";
1447 }
1449 }
1450 }
1451
1452 return (ConstElementPtr());
1453}
1454
1458
1459 if (!srv) {
1461 "Server object not initialized, can't process config.");
1462 return (no_srv);
1463 }
1464
1466 .arg(srv->redactConfig(config)->str());
1467
1468 return (configureDhcp4Server(*srv, config, true));
1469}
1470
1471ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
1472 uint16_t client_port /*= 0*/)
1473 : Dhcpv4Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1474 if (getInstance()) {
1476 "There is another Dhcpv4Srv instance already.");
1477 }
1478 server_ = this; // remember this instance for later use in handlers
1479
1480 // ProcessSpawn uses IO service to handle signal set events.
1482
1483 // TimerMgr uses IO service to run asynchronous timers.
1484 TimerMgr::instance()->setIOService(getIOService());
1485
1486 // Command managers use IO service to run asynchronous socket operations.
1489
1490 // Set the HTTP authentication default realm.
1492
1493 // DatabaseConnection uses IO service to run asynchronous timers.
1495
1496 // These are the commands always supported by the DHCPv4 server.
1497 // Please keep the list in alphabetic order.
1498 CommandMgr::instance().registerCommand("build-report",
1499 std::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1500
1501 CommandMgr::instance().registerCommand("config-backend-pull",
1502 std::bind(&ControlledDhcpv4Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1503
1505 std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1506
1507 CommandMgr::instance().registerCommand("config-hash-get",
1508 std::bind(&ControlledDhcpv4Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1509
1510 CommandMgr::instance().registerCommand("config-reload",
1511 std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1512
1514 std::bind(&ControlledDhcpv4Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1515
1516 CommandMgr::instance().registerCommand("config-test",
1517 std::bind(&ControlledDhcpv4Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1518
1519 CommandMgr::instance().registerCommand("config-write",
1520 std::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1521
1522 CommandMgr::instance().registerCommand("dhcp-enable",
1523 std::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1524
1525 CommandMgr::instance().registerCommand("dhcp-disable",
1526 std::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1527
1528 CommandMgr::instance().registerCommand("kea-lfc-start",
1529 std::bind(&ControlledDhcpv4Srv::commandLfcStartHandler, this, ph::_1, ph::_2));
1530
1531 CommandMgr::instance().registerCommand("leases-reclaim",
1532 std::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1533
1534 CommandMgr::instance().registerCommand("subnet4-select-test",
1535 std::bind(&ControlledDhcpv4Srv::commandSubnet4SelectTestHandler, this, ph::_1, ph::_2));
1536
1537 CommandMgr::instance().registerCommand("subnet4o6-select-test",
1538 std::bind(&ControlledDhcpv4Srv::commandSubnet4o6SelectTestHandler, this, ph::_1, ph::_2));
1539
1540 CommandMgr::instance().registerCommand("server-tag-get",
1541 std::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1542
1544 std::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1545
1547 std::bind(&ControlledDhcpv4Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1548
1549 CommandMgr::instance().registerCommand("version-get",
1550 std::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1551
1552 // Register statistic related commands
1553 CommandMgr::instance().registerCommand("statistic-get",
1554 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1555
1556 CommandMgr::instance().registerCommand("statistic-reset",
1557 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1558
1559 CommandMgr::instance().registerCommand("statistic-remove",
1560 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1561
1562 CommandMgr::instance().registerCommand("statistic-get-all",
1563 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1564
1565 CommandMgr::instance().registerCommand("statistic-global-get-all",
1566 std::bind(&StatsMgr::statisticGlobalGetAllHandler, ph::_1, ph::_2));
1567
1568 CommandMgr::instance().registerCommand("statistic-reset-all",
1569 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1570
1571 CommandMgr::instance().registerCommand("statistic-remove-all",
1572 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1573
1574 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1575 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1576
1577 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1578 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1579
1580 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1581 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1582
1583 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1584 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1585}
1586
1588 setExitValue(exit_value);
1589 getIOService()->stop(); // Stop ASIO transmissions
1590 shutdown(); // Initiate DHCPv4 shutdown procedure.
1591}
1592
1594 try {
1595 MultiThreadingMgr::instance().apply(false, 0, 0);
1598
1599 // The closure captures either a shared pointer (memory leak)
1600 // or a raw pointer (pointing to a deleted object).
1604
1605 timer_mgr_->unregisterTimers();
1606
1607 cleanup();
1608
1609 // Close command sockets.
1612
1613 // Deregister any registered commands (please keep in alphabetic order)
1614 CommandMgr::instance().deregisterCommand("build-report");
1615 CommandMgr::instance().deregisterCommand("config-backend-pull");
1617 CommandMgr::instance().deregisterCommand("config-hash-get");
1618 CommandMgr::instance().deregisterCommand("config-reload");
1620 CommandMgr::instance().deregisterCommand("config-test");
1621 CommandMgr::instance().deregisterCommand("config-write");
1622 CommandMgr::instance().deregisterCommand("dhcp-disable");
1623 CommandMgr::instance().deregisterCommand("dhcp-enable");
1624 CommandMgr::instance().deregisterCommand("kea-lfc-start");
1625 CommandMgr::instance().deregisterCommand("leases-reclaim");
1626 CommandMgr::instance().deregisterCommand("subnet4-select-test");
1627 CommandMgr::instance().deregisterCommand("subnet4o6-select-test");
1628 CommandMgr::instance().deregisterCommand("server-tag-get");
1630 CommandMgr::instance().deregisterCommand("statistic-get");
1631 CommandMgr::instance().deregisterCommand("statistic-get-all");
1632 CommandMgr::instance().deregisterCommand("statistic-global-get-all");
1633 CommandMgr::instance().deregisterCommand("statistic-remove");
1634 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1635 CommandMgr::instance().deregisterCommand("statistic-reset");
1636 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1637 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1638 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1639 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1640 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1642 CommandMgr::instance().deregisterCommand("version-get");
1643
1644 // Reset DatabaseConnection IO service.
1646 } catch (...) {
1647 // Don't want to throw exceptions from the destructor. The server
1648 // is shutting down anyway.
1649 }
1650
1651 server_ = NULL; // forget this instance. There should be no callback anymore
1652 // at this stage anyway.
1653}
1654
1655void
1656ControlledDhcpv4Srv::reclaimExpiredLeases(const size_t max_leases,
1657 const uint16_t timeout,
1658 const bool remove_lease,
1659 const uint16_t max_unwarned_cycles) {
1660 try {
1661 if (network_state_->isServiceEnabled()) {
1662 server_->alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
1663 remove_lease,
1664 max_unwarned_cycles);
1665 } else {
1667 .arg(CfgMgr::instance().getCurrentCfg()->
1668 getCfgExpiration()->getReclaimTimerWaitTime());
1669 }
1670 } catch (const std::exception& ex) {
1672 .arg(ex.what());
1673 }
1674 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1676}
1677
1678void
1679ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1680 if (network_state_->isServiceEnabled()) {
1681 server_->alloc_engine_->deleteExpiredReclaimedLeases4(secs);
1682 }
1683
1684 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1686}
1687
1688bool
1689ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1690 if (!db_reconnect_ctl) {
1691 // This should never happen
1693 return (false);
1694 }
1695
1696 // Disable service until the connection is recovered.
1697 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1698 db_reconnect_ctl->alterServiceState()) {
1699 network_state_->disableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1700 }
1701
1703 .arg(db_reconnect_ctl->id())
1704 .arg(db_reconnect_ctl->timerName());;
1705
1706 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1707 // return false.
1708 if (!db_reconnect_ctl->retriesLeft() ||
1709 !db_reconnect_ctl->retryInterval()) {
1711 .arg(db_reconnect_ctl->retriesLeft())
1712 .arg(db_reconnect_ctl->retryInterval())
1713 .arg(db_reconnect_ctl->id())
1714 .arg(db_reconnect_ctl->timerName());
1715 if (db_reconnect_ctl->exitOnFailure()) {
1716 shutdownServer(EXIT_FAILURE);
1717 }
1718 return (false);
1719 }
1720
1721 return (true);
1722}
1723
1724bool
1725ControlledDhcpv4Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1726 if (!db_reconnect_ctl) {
1727 // This should never happen
1729 return (false);
1730 }
1731
1732 // Enable service after the connection is recovered.
1733 if (db_reconnect_ctl->retriesLeft() != db_reconnect_ctl->maxRetries() &&
1734 db_reconnect_ctl->alterServiceState()) {
1735 network_state_->enableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1736 }
1737
1739 .arg(db_reconnect_ctl->id())
1740 .arg(db_reconnect_ctl->timerName());
1741
1742 db_reconnect_ctl->resetRetries();
1743
1744 return (true);
1745}
1746
1747bool
1748ControlledDhcpv4Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1749 if (!db_reconnect_ctl) {
1750 // This should never happen
1752 return (false);
1753 }
1754
1756 .arg(db_reconnect_ctl->maxRetries())
1757 .arg(db_reconnect_ctl->id())
1758 .arg(db_reconnect_ctl->timerName());
1759
1760 if (db_reconnect_ctl->exitOnFailure()) {
1761 shutdownServer(EXIT_FAILURE);
1762 }
1763
1764 return (true);
1765}
1766
1767void
1768ControlledDhcpv4Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1769 if (!reconnect_ctl) {
1770 // This should never happen
1772 return;
1773 }
1774
1776 .arg(reconnect_ctl->maxRetries());
1777
1778 if (reconnect_ctl->exitOnFailure()) {
1779 shutdownServer(EXIT_FAILURE);
1780 }
1781}
1782
1783void
1784ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1785 boost::shared_ptr<unsigned> failure_count) {
1786 // stop thread pool (if running)
1787 MultiThreadingCriticalSection cs;
1788
1789 try {
1790 // Fetch any configuration backend updates since our last fetch.
1791 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1792 CBControlDHCPv4::FetchMode::FETCH_UPDATE);
1793 (*failure_count) = 0;
1794
1795 } catch (const std::exception& ex) {
1797 .arg(ex.what());
1798
1799 // We allow at most 10 consecutive failures after which we stop
1800 // making further attempts to fetch the configuration updates.
1801 // Let's return without re-scheduling the timer.
1802 if (++(*failure_count) > 10) {
1805 return;
1806 }
1807 }
1808
1809 // Reschedule the timer to fetch new updates or re-try if
1810 // the previous attempt resulted in an error.
1811 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1812 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1813 }
1814}
1815
1816} // namespace dhcp
1817} // namespace isc
CtrlAgentHooks Hooks
@ map
Definition data.h:160
@ integer
Definition data.h:153
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
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.
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.
static OpenSocketsFailedCallback open_sockets_failed_callback_
Optional callback function to invoke if all retries of the opening sockets fail.
Definition cfg_iface.h:361
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc: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.
virtual ~ControlledDhcpv4Srv()
Destructor.
static isc::data::ConstElementPtr finishConfigHookLibraries(isc::data::ConstElementPtr config)
Configuration checker for hook libraries.
isc::data::ConstElementPtr loadConfigFile(const std::string &file_name)
Configure DHCPv4 server using the configuration file specified.
void cleanup()
Performs cleanup, immediately before termination.
ControlledDhcpv4Srv(uint16_t server_port=DHCP4_SERVER_PORT, uint16_t client_port=0)
Constructor.
static isc::data::ConstElementPtr checkConfig(isc::data::ConstElementPtr config)
Configuration checker.
void init(const std::string &config_file)
Initializes the server.
static isc::data::ConstElementPtr processConfig(isc::data::ConstElementPtr config)
Configuration processor.
static ControlledDhcpv4Srv * getInstance()
Returns pointer to the sole instance of Dhcpv4Srv.
virtual void shutdownServer(int exit_value)
Initiates shutdown procedure for the whole DHCPv4 server.
static Dhcp4to6Ipc & instance()
Returns pointer to the sole instance of Dhcp4to6Ipc.
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:319
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
Definition dhcp4_srv.h:1265
NetworkStatePtr & getNetworkState()
Returns pointer to the network state used by the server.
Definition dhcp4_srv.h:324
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
bool useBroadcast() const
Return bool value indicating that broadcast flags should be set on sockets.
Definition dhcp4_srv.h:464
NetworkStatePtr network_state_
Holds information about disabled DHCP service and/or disabled subnet/network scopes.
Definition dhcp4_srv.h:1272
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
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:49
static TrackingLeaseMgr & instance()
Return current lease manager.
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
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)
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
static StatsMgr & instance()
Statistics Manager accessor method.
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.
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_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:118
std::string getConfigReport()
Definition cfgrpt.cc:20
const isc::log::MessageID DHCP4_NOT_RUNNING
const isc::log::MessageID DHCP4_DYNAMIC_RECONFIGURATION_FAIL
const isc::log::MessageID DHCP4_CONFIG_RECEIVED
const isc::log::MessageID DHCP4_DYNAMIC_RECONFIGURATION_SUCCESS
boost::shared_ptr< const Subnet4 > ConstSubnet4Ptr
A const pointer to a Subnet4 object.
Definition subnet.h:458
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:514
const isc::log::MessageID DHCP4_DB_RECONNECT_NO_DB_CTL
const isc::log::MessageID DHCP4_CB_PERIODIC_FETCH_UPDATES_RETRIES_EXHAUSTED
const isc::log::MessageID DHCP4_CONFIG_PACKET_QUEUE
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
const isc::log::MessageID DHCP4_CB_ON_DEMAND_FETCH_UPDATES_FAIL
const isc::log::MessageID DHCP4_CONFIG_LOAD_FAIL
const int DBG_DHCP4_COMMAND
Debug level used to log receiving commands.
Definition dhcp4_log.h:30
const isc::log::MessageID DHCP4_DB_RECONNECT_DISABLED
const isc::log::MessageID DHCP4_CONFIG_UNRECOVERABLE_ERROR
const 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.
PerfMonMgrPtr mgr
PerfMonMgr singleton.
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.
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.