Kea 3.1.1
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
379 ConstElementPtr lease_database = dhcp4->get("lease-database");
380 if (lease_database) {
381 db::DbAccessParser parser;
382 std::string access_string;
383 parser.parse(access_string, lease_database);
384 auto params = parser.getDbAccessParameters();
385 if (params["type"] == "memfile") {
386 string file_name = params["name"];
389 "Can not update configuration while lease file cleanup process is running."));
390 }
391 }
392 }
393
394 // stop thread pool (if running)
395 MultiThreadingCriticalSection cs;
396
397 // We are starting the configuration process so we should remove any
398 // staging configuration that has been created during previous
399 // configuration attempts.
401
402 // Parse the logger configuration explicitly into the staging config.
403 // Note this does not alter the current loggers, they remain in
404 // effect until we apply the logging config below. If no logging
405 // is supplied logging will revert to default logging.
406 Daemon::configureLogger(dhcp4, CfgMgr::instance().getStagingCfg());
407
408 // Let's apply the new logging. We do it early, so we'll be able to print
409 // out what exactly is wrong with the new config in case of problems.
410 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
411
412 // Now we configure the server proper.
413 ConstElementPtr result = processConfig(dhcp4);
414
415 // If the configuration parsed successfully, apply the new logger
416 // configuration and then commit the new configuration. We apply
417 // the logging first in case there's a configuration failure.
418 int rcode = 0;
419 isc::config::parseAnswer(rcode, result);
420 if (rcode == CONTROL_RESULT_SUCCESS) {
421 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
422
423 // Use new configuration.
425 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
426 // Ok, we applied the logging from the upcoming configuration, but
427 // there were problems with the config. As such, we need to back off
428 // and revert to the previous logging configuration. This is not done if
429 // sequence == 0, because that would mean always reverting to stdout by
430 // default, and it is arguably more helpful to have the error in a
431 // potential file or syslog configured in the upcoming configuration.
432 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
433
434 // Not initial configuration so someone can believe we reverted
435 // to the previous configuration. It is not the case so be clear
436 // about this.
438 }
439
441 try {
442 // Handle events registered by hooks using external IOService objects.
444 } catch (const std::exception& ex) {
445 std::ostringstream err;
446 err << "Error initializing hooks: "
447 << ex.what();
449 }
450
451 return (result);
452}
453
455ControlledDhcpv4Srv::commandConfigTestHandler(const string&,
456 ConstElementPtr args) {
457 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
458 ConstElementPtr dhcp4;
459 string message;
460
461 // Command arguments are expected to be:
462 // { "Dhcp4": { ... } }
463 if (!args) {
464 message = "Missing mandatory 'arguments' parameter.";
465 } else {
466 dhcp4 = args->get("Dhcp4");
467 if (!dhcp4) {
468 message = "Missing mandatory 'Dhcp4' parameter.";
469 } else if (dhcp4->getType() != Element::map) {
470 message = "'Dhcp4' parameter expected to be a map.";
471 }
472 }
473
474 // Check unsupported objects.
475 if (message.empty()) {
476 for (auto const& obj : args->mapValue()) {
477 const string& obj_name = obj.first;
478 if (obj_name != "Dhcp4") {
480 .arg(obj_name);
481 if (message.empty()) {
482 message = "Unsupported '" + obj_name + "' parameter";
483 } else {
484 message += " (and '" + obj_name + "')";
485 }
486 }
487 }
488 if (!message.empty()) {
489 message += ".";
490 }
491 }
492
493 if (!message.empty()) {
494 // Something is amiss with arguments, return a failure response.
495 ConstElementPtr result = isc::config::createAnswer(status_code,
496 message);
497 return (result);
498 }
499
500 // stop thread pool (if running)
501 MultiThreadingCriticalSection cs;
502
503 // We are starting the configuration process so we should remove any
504 // staging configuration that has been created during previous
505 // configuration attempts.
507
508 // Now we check the server proper.
509 return (checkConfig(dhcp4));
510}
511
513ControlledDhcpv4Srv::commandDhcpDisableHandler(const std::string&,
514 ConstElementPtr args) {
515 std::ostringstream message;
516 int64_t max_period = 0;
517 std::string origin;
518
519 // If the args map does not contain 'origin' parameter, the default type
520 // will be used (user command).
521 auto type = NetworkState::USER_COMMAND;
522
523 // Parse arguments to see if the 'max-period' or 'origin' parameters have
524 // been specified.
525 if (args) {
526 // Arguments must be a map.
527 if (args->getType() != Element::map) {
528 message << "arguments for the 'dhcp-disable' command must be a map";
529
530 } else {
531 ConstElementPtr max_period_element = args->get("max-period");
532 // max-period is optional.
533 if (max_period_element) {
534 // It must be an integer, if specified.
535 if (max_period_element->getType() != Element::integer) {
536 message << "'max-period' argument must be a number";
537
538 } else {
539 // It must be positive integer.
540 max_period = max_period_element->intValue();
541 if (max_period <= 0) {
542 message << "'max-period' must be positive integer";
543 }
544 }
545 }
546 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
547 // stable release. However, the 'origin' is kept for backward compatibility
548 // with Kea versions before 2.5.8. It is common to receive both parameters
549 // because HA hook library sends both in case the partner server hasn't been
550 // upgraded to the new version. The 'origin-id' takes precedence over the
551 // 'origin'.
552 ConstElementPtr origin_id_element = args->get("origin-id");
553 ConstElementPtr origin_element = args->get("origin");
554 // The 'origin-id' and 'origin' arguments are optional.
555 if (origin_id_element) {
556 if (origin_id_element->getType() == Element::integer) {
557 type = origin_id_element->intValue();
558 } else {
559 message << "'origin-id' argument must be a number";
560 }
561 } else if (origin_element) {
562 switch (origin_element->getType()) {
563 case Element::string:
564 origin = origin_element->stringValue();
565 if (origin == "ha-partner") {
567 } else if (origin != "user") {
568 if (origin.empty()) {
569 origin = "(empty string)";
570 }
571 message << "invalid value used for 'origin' parameter: "
572 << origin;
573 }
574 break;
575 case Element::integer:
576 type = origin_element->intValue();
577 break;
578 default:
579 // It must be a string or a number, if specified.
580 message << "'origin' argument must be a string or a number";
581 }
582 }
583 }
584 }
585
586 // No error occurred, so let's disable the service.
587 if (message.tellp() == 0) {
588 message << "DHCPv4 service disabled";
589 if (max_period > 0) {
590 message << " for " << max_period << " seconds";
591
592 // The user specified that the DHCP service should resume not
593 // later than in max-period seconds. If the 'dhcp-enable' command
594 // is not sent, the DHCP service will resume automatically.
595 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
596 type);
597 }
598 network_state_->disableService(type);
599
600 // Success.
601 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
602 }
603
604 // Failure.
605 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
606}
607
609ControlledDhcpv4Srv::commandDhcpEnableHandler(const std::string&,
610 ConstElementPtr args) {
611 std::ostringstream message;
612 std::string origin;
613
614 // If the args map does not contain 'origin' parameter, the default type
615 // will be used (user command).
616 auto type = NetworkState::USER_COMMAND;
617
618 // Parse arguments to see if the 'origin' parameter has been specified.
619 if (args) {
620 // Arguments must be a map.
621 if (args->getType() != Element::map) {
622 message << "arguments for the 'dhcp-enable' command must be a map";
623
624 } else {
625 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
626 // stable release. However, the 'origin' is kept for backward compatibility
627 // with Kea versions before 2.5.8. It is common to receive both parameters
628 // because HA hook library sends both in case the partner server hasn't been
629 // upgraded to the new version. The 'origin-id' takes precedence over the
630 // 'origin'.
631 ConstElementPtr origin_id_element = args->get("origin-id");
632 ConstElementPtr origin_element = args->get("origin");
633 // The 'origin-id' and 'origin' arguments are optional.
634 if (origin_id_element) {
635 if (origin_id_element->getType() == Element::integer) {
636 type = origin_id_element->intValue();
637 } else {
638 message << "'origin-id' argument must be a number";
639 }
640 } else if (origin_element) {
641 switch (origin_element->getType()) {
642 case Element::string:
643 origin = origin_element->stringValue();
644 if (origin == "ha-partner") {
646 } else if (origin != "user") {
647 if (origin.empty()) {
648 origin = "(empty string)";
649 }
650 message << "invalid value used for 'origin' parameter: "
651 << origin;
652 }
653 break;
654 case Element::integer:
655 type = origin_element->intValue();
656 break;
657 default:
658 // It must be a string or a number, if specified.
659 message << "'origin' argument must be a string or a number";
660 }
661 }
662 }
663 }
664
665 // No error occurred, so let's enable the service.
666 if (message.tellp() == 0) {
667 network_state_->enableService(type);
668
669 // Success.
671 "DHCP service successfully enabled"));
672 }
673
674 // Failure.
675 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
676}
677
679ControlledDhcpv4Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
681 ElementPtr arguments = Element::createMap();
682 arguments->set("extended", extended);
685 arguments);
686 return (answer);
687}
688
690ControlledDhcpv4Srv::commandBuildReportHandler(const string&,
692 ConstElementPtr answer =
694 return (answer);
695}
696
698ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
699 ConstElementPtr args) {
700 int status_code = CONTROL_RESULT_ERROR;
701 string message;
702
703 // args must be { "remove": <bool> }
704 if (!args) {
705 message = "Missing mandatory 'remove' parameter.";
706 } else {
707 ConstElementPtr remove_name = args->get("remove");
708 if (!remove_name) {
709 message = "Missing mandatory 'remove' parameter.";
710 } else if (remove_name->getType() != Element::boolean) {
711 message = "'remove' parameter expected to be a boolean.";
712 } else {
713 bool remove_lease = remove_name->boolValue();
714 server_->alloc_engine_->reclaimExpiredLeases4(0, 0, remove_lease);
715 status_code = 0;
716 message = "Reclamation of expired leases is complete.";
717 }
718 }
719 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
720 return (answer);
721}
722
724ControlledDhcpv4Srv::commandSubnet4SelectTestHandler(const string&,
725 ConstElementPtr args) {
726 if (!args) {
727 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
728 }
729 if (args->getType() != Element::map) {
730 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
731 }
732 bool ignore_link_sel =
733 CfgMgr::instance().getCurrentCfg()->getIgnoreRAILinkSelection();
734 SubnetSelector selector;
735 for (auto const& entry : args->mapValue()) {
736 ostringstream errmsg;
737 if (entry.first == "interface") {
738 if (entry.second->getType() != Element::string) {
739 errmsg << "'interface' entry must be a string";
740 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
741 }
742 selector.iface_name_ = entry.second->stringValue();
743 continue;
744 } else if (entry.first == "address") {
745 if (entry.second->getType() != Element::string) {
746 errmsg << "'address' entry must be a string";
747 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
748 }
749 try {
750 IOAddress addr(entry.second->stringValue());
751 if (!addr.isV4()) {
752 errmsg << "bad 'address' entry: not IPv4";
753 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
754 }
755 selector.ciaddr_ = addr;
756 continue;
757 } catch (const exception& ex) {
758 errmsg << "bad 'address' entry: " << ex.what();
759 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
760 }
761 } else if (entry.first == "relay") {
762 if (entry.second->getType() != Element::string) {
763 errmsg << "'relay' entry must be a string";
764 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
765 }
766 try {
767 IOAddress addr(entry.second->stringValue());
768 if (!addr.isV4()) {
769 errmsg << "bad 'relay' entry: not IPv4";
770 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
771 }
772 selector.giaddr_ = addr;
773 continue;
774 } catch (const exception& ex) {
775 errmsg << "bad 'relay' entry: " << ex.what();
776 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
777 }
778 } else if (entry.first == "local") {
779 if (entry.second->getType() != Element::string) {
780 errmsg << "'local' entry must be a string";
781 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
782 }
783 try {
784 IOAddress addr(entry.second->stringValue());
785 if (!addr.isV4()) {
786 errmsg << "bad 'local' entry: not IPv4";
787 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
788 }
789 selector.local_address_ = addr;
790 continue;
791 } catch (const exception& ex) {
792 errmsg << "bad 'local' entry: " << ex.what();
793 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
794 }
795 } else if (entry.first == "remote") {
796 if (entry.second->getType() != Element::string) {
797 errmsg << "'remote' entry must be a string";
798 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
799 }
800 try {
801 IOAddress addr(entry.second->stringValue());
802 if (!addr.isV4()) {
803 errmsg << "bad 'remote' entry: not IPv4";
804 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
805 }
806 selector.remote_address_ = addr;
807 continue;
808 } catch (const exception& ex) {
809 errmsg << "bad 'remote' entry: " << ex.what();
810 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
811 }
812 } else if (entry.first == "link") {
813 if (entry.second->getType() != Element::string) {
814 errmsg << "'link' entry must be a string";
815 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
816 }
817 try {
818 IOAddress addr(entry.second->stringValue());
819 if (!addr.isV4()) {
820 errmsg << "bad 'link' entry: not IPv4";
821 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
822 }
823 if (!ignore_link_sel) {
824 selector.option_select_ = addr;
825 }
826 continue;
827 } catch (const exception& ex) {
828 errmsg << "bad 'link' entry: " << ex.what();
829 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
830 }
831 } else if (entry.first == "subnet") {
832 // RAI link-selection has precedence over subnet-selection.
833 if (args->contains("link") && !ignore_link_sel) {
834 continue;
835 }
836 if (entry.second->getType() != Element::string) {
837 errmsg << "'subnet' entry must be a string";
838 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
839 }
840 try {
841 IOAddress addr(entry.second->stringValue());
842 if (!addr.isV4()) {
843 errmsg << "bad 'subnet' entry: not IPv4";
844 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
845 }
846 selector.option_select_ = addr;
847 continue;
848 } catch (const exception& ex) {
849 errmsg << "bad 'subnet' entry: " << ex.what();
850 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
851 }
852 } else if (entry.first == "classes") {
853 if (entry.second->getType() != Element::list) {
855 "'classes' entry must be a list"));
856 }
857 for (auto const& item : entry.second->listValue()) {
858 if (!item || (item->getType() != Element::string)) {
859 errmsg << "'classes' entry must be a list of strings";
860 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
861 }
862 // Skip empty client classes.
863 if (!item->stringValue().empty()) {
864 selector.client_classes_.insert(item->stringValue());
865 }
866 }
867 continue;
868 } else {
869 errmsg << "unknown entry '" << entry.first << "'";
870 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
871 }
872 }
874 getCfgSubnets4()->selectSubnet(selector);
875 if (!subnet) {
876 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
877 }
878 SharedNetwork4Ptr network;
879 subnet->getSharedNetwork(network);
880 ostringstream msg;
881 if (network) {
882 msg << "selected shared network '" << network->getName()
883 << "' starting with subnet '" << subnet->toText()
884 << "' id " << subnet->getID();
885 } else {
886 msg << "selected subnet '" << subnet->toText()
887 << "' id " << subnet->getID();
888 }
889 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
890}
891
893ControlledDhcpv4Srv::commandSubnet4o6SelectTestHandler(const string&,
894 ConstElementPtr args) {
895 if (!args) {
896 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
897 }
898 if (args->getType() != Element::map) {
899 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
900 }
901 SubnetSelector selector;
902 selector.dhcp4o6_ = true;
905 for (auto const& entry : args->mapValue()) {
906 ostringstream errmsg;
907 if (entry.first == "interface") {
908 if (entry.second->getType() != Element::string) {
909 errmsg << "'interface' entry must be a string";
910 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
911 }
912 selector.iface_name_ = entry.second->stringValue();
913 continue;
914 } if (entry.first == "interface-id") {
915 if (entry.second->getType() != Element::string) {
916 errmsg << "'interface-id' entry must be a string";
917 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
918 }
919 try {
920 string str = entry.second->stringValue();
921 vector<uint8_t> id = util::str::quotedStringToBinary(str);
922 if (id.empty()) {
924 }
925 if (id.empty()) {
926 errmsg << "'interface-id' must be not empty";
927 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
928 }
929 selector.interface_id_ = OptionPtr(new Option(Option::V6,
931 id));
932 continue;
933 } catch (...) {
934 errmsg << "value of 'interface-id' was not recognized";
935 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
936 }
937 } else if (entry.first == "address") {
938 if (entry.second->getType() != Element::string) {
939 errmsg << "'address' entry must be a string";
940 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
941 }
942 try {
943 IOAddress addr(entry.second->stringValue());
944 if (!addr.isV4()) {
945 errmsg << "bad 'address' entry: not IPv4";
946 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
947 }
948 selector.ciaddr_ = addr;
949 continue;
950 } catch (const exception& ex) {
951 errmsg << "bad 'address' entry: " << ex.what();
952 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
953 }
954 } else if (entry.first == "relay") {
955 if (entry.second->getType() != Element::string) {
956 errmsg << "'relay' entry must be a string";
957 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
958 }
959 try {
960 IOAddress addr(entry.second->stringValue());
961 if (!addr.isV4()) {
962 errmsg << "bad 'relay' entry: not IPv4";
963 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
964 }
965 selector.giaddr_ = addr;
966 continue;
967 } catch (const exception& ex) {
968 errmsg << "bad 'relay' entry: " << ex.what();
969 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
970 }
971 } else if (entry.first == "local") {
972 if (entry.second->getType() != Element::string) {
973 errmsg << "'local' entry must be a string";
974 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
975 }
976 try {
977 IOAddress addr(entry.second->stringValue());
978 if (!addr.isV6()) {
979 errmsg << "bad 'local' entry: not IPv6";
980 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
981 }
982 selector.local_address_ = addr;
983 continue;
984 } catch (const exception& ex) {
985 errmsg << "bad 'local' entry: " << ex.what();
986 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
987 }
988 } else if (entry.first == "remote") {
989 if (entry.second->getType() != Element::string) {
990 errmsg << "'remote' entry must be a string";
991 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
992 }
993 try {
994 IOAddress addr(entry.second->stringValue());
995 if (!addr.isV6()) {
996 errmsg << "bad 'remote' entry: not IPv6";
997 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
998 }
999 selector.remote_address_ = addr;
1000 continue;
1001 } catch (const exception& ex) {
1002 errmsg << "bad 'remote' entry: " << ex.what();
1003 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1004 }
1005 } else if (entry.first == "link") {
1006 if (entry.second->getType() != Element::string) {
1007 errmsg << "'link' entry must be a string";
1008 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1009 }
1010 try {
1011 IOAddress addr(entry.second->stringValue());
1012 if (!addr.isV6()) {
1013 errmsg << "bad 'link' entry: not IPv6";
1014 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1015 }
1016 selector.first_relay_linkaddr_ = addr;
1017 continue;
1018 } catch (const exception& ex) {
1019 errmsg << "bad 'link' entry: " << ex.what();
1020 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1021 }
1022 } else if (entry.first == "subnet") {
1023 if (entry.second->getType() != Element::string) {
1024 errmsg << "'subnet' entry must be a string";
1025 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1026 }
1027 try {
1028 IOAddress addr(entry.second->stringValue());
1029 if (!addr.isV4()) {
1030 errmsg << "bad 'subnet' entry: not IPv4";
1031 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1032 }
1033 selector.option_select_ = addr;
1034 continue;
1035 } catch (const exception& ex) {
1036 errmsg << "bad 'subnet' entry: " << ex.what();
1037 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1038 }
1039 } else if (entry.first == "classes") {
1040 if (entry.second->getType() != Element::list) {
1042 "'classes' entry must be a list"));
1043 }
1044 for (auto const& item : entry.second->listValue()) {
1045 if (!item || (item->getType() != Element::string)) {
1046 errmsg << "'classes' entry must be a list of strings";
1047 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1048 }
1049 // Skip empty client classes.
1050 if (!item->stringValue().empty()) {
1051 selector.client_classes_.insert(item->stringValue());
1052 }
1053 }
1054 continue;
1055 } else {
1056 errmsg << "unknown entry '" << entry.first << "'";
1057 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1058 }
1059 }
1061 getCfgSubnets4()->selectSubnet4o6(selector);
1062 if (!subnet) {
1063 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
1064 }
1065 SharedNetwork4Ptr network;
1066 subnet->getSharedNetwork(network);
1067 ostringstream msg;
1068 if (network) {
1069 msg << "selected shared network '" << network->getName()
1070 << "' starting with subnet '" << subnet->toText()
1071 << "' id " << subnet->getID();
1072 } else {
1073 msg << "selected subnet '" << subnet->toText()
1074 << "' id " << subnet->getID();
1075 }
1076 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
1077}
1078
1080ControlledDhcpv4Srv::commandServerTagGetHandler(const std::string&,
1082 const std::string& tag =
1083 CfgMgr::instance().getCurrentCfg()->getServerTag();
1084 ElementPtr response = Element::createMap();
1085 response->set("server-tag", Element::create(tag));
1086
1087 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
1088}
1089
1091ControlledDhcpv4Srv::commandConfigBackendPullHandler(const std::string&,
1093 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
1094 if (!ctl_info) {
1095 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
1096 }
1097
1098 // stop thread pool (if running)
1099 MultiThreadingCriticalSection cs;
1100
1101 // Reschedule the periodic CB fetch.
1102 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1103 TimerMgr::instance()->cancel("Dhcp4CBFetchTimer");
1104 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1105 }
1106
1107 // Code from cbFetchUpdates.
1108 // The configuration to use is the current one because this is called
1109 // after the configuration manager commit.
1110 try {
1111 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
1112 auto mode = CBControlDHCPv4::FetchMode::FETCH_UPDATE;
1113 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
1114 } catch (const std::exception& ex) {
1116 .arg(ex.what());
1118 "On demand configuration update failed: " +
1119 string(ex.what())));
1120 }
1122 "On demand configuration update successful."));
1123}
1124
1126ControlledDhcpv4Srv::commandStatusGetHandler(const string&,
1127 ConstElementPtr /*args*/) {
1128 ElementPtr status = Element::createMap();
1129 status->set("pid", Element::create(static_cast<int>(getpid())));
1130
1131 auto now = boost::posix_time::second_clock::universal_time();
1132 // Sanity check: start_ is always initialized.
1133 if (!start_.is_not_a_date_time()) {
1134 auto uptime = now - start_;
1135 status->set("uptime", Element::create(uptime.total_seconds()));
1136 }
1137
1138 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
1139 if (!last_commit.is_not_a_date_time()) {
1140 auto reload = now - last_commit;
1141 status->set("reload", Element::create(reload.total_seconds()));
1142 }
1143
1144 auto& mt_mgr = MultiThreadingMgr::instance();
1145 if (mt_mgr.getMode()) {
1146 status->set("multi-threading-enabled", Element::create(true));
1147 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
1148 MultiThreadingMgr::instance().getThreadPoolSize())));
1149 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
1150 MultiThreadingMgr::instance().getPacketQueueSize())));
1151 ElementPtr queue_stats = Element::createList();
1152 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
1153 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
1154 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
1155 status->set("packet-queue-statistics", queue_stats);
1156
1157 } else {
1158 status->set("multi-threading-enabled", Element::create(false));
1159 }
1160
1161 // Iterate through the interfaces and get all the errors.
1162 ElementPtr socket_errors(Element::createList());
1163 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
1164 for (std::string const& error : interface->getErrors()) {
1165 socket_errors->add(Element::create(error));
1166 }
1167 }
1168
1169 // Abstract the information from all sockets into a single status.
1170 ElementPtr sockets(Element::createMap());
1171 if (socket_errors->empty()) {
1172 sockets->set("status", Element::create("ready"));
1173 } else {
1174 ReconnectCtlPtr const reconnect_ctl(
1175 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
1176 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
1177 sockets->set("status", Element::create("retrying"));
1178 } else {
1179 sockets->set("status", Element::create("failed"));
1180 }
1181 sockets->set("errors", socket_errors);
1182 }
1183 status->set("sockets", sockets);
1184
1185 status->set("dhcp-state", network_state_->toElement());
1186
1187 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
1188}
1189
1191ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
1192 ConstElementPtr args) {
1193 StatsMgr& stats_mgr = StatsMgr::instance();
1195 // Update the default parameter.
1196 long max_samples = stats_mgr.getMaxSampleCountDefault();
1197 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1198 "statistic-default-sample-count", Element::create(max_samples));
1199 return (answer);
1200}
1201
1203ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
1204 ConstElementPtr args) {
1205 StatsMgr& stats_mgr = StatsMgr::instance();
1206 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleAgeAllHandler(args);
1207 // Update the default parameter.
1208 auto duration = stats_mgr.getMaxSampleAgeDefault();
1209 long max_age = toSeconds(duration);
1210 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1211 "statistic-default-sample-age", Element::create(max_age));
1212 return (answer);
1213}
1214
1218
1219 // Allow DB reconnect on startup. The database connection parameters specify
1220 // respective details.
1222
1223 // Single stream instance used in all error clauses
1224 std::ostringstream err;
1225
1226 if (!srv) {
1227 err << "Server object not initialized, can't process config.";
1229 }
1230
1232 .arg(srv->redactConfig(config)->str());
1233
1234 // Destroy lease manager before hooks unload.
1236
1237 // Destroy host manager before hooks unload.
1239
1241
1242 // Check that configuration was successful. If not, do not reopen sockets
1243 // and don't bother with DDNS stuff.
1244 try {
1245 int rcode = 0;
1246 isc::config::parseAnswer(rcode, answer);
1247 if (rcode != 0) {
1248 return (answer);
1249 }
1250 } catch (const std::exception& ex) {
1251 err << "Failed to process configuration:" << ex.what();
1253 }
1254
1255 // Re-open lease and host database with new parameters.
1256 try {
1258 std::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, ph::_1);
1259
1261 std::bind(&ControlledDhcpv4Srv::dbRecoveredCallback, srv, ph::_1);
1262
1264 std::bind(&ControlledDhcpv4Srv::dbFailedCallback, srv, ph::_1);
1265
1266 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
1267 string params = "universe=4";
1268 cfg_db->setAppendedParameters(params);
1269 cfg_db->createManagers();
1270 // Reset counters related to connections as all managers have been recreated.
1271 srv->getNetworkState()->resetForDbConnection();
1272 srv->getNetworkState()->resetForLocalCommands();
1273 srv->getNetworkState()->resetForRemoteCommands();
1274 } catch (const std::exception& ex) {
1275 err << "Unable to open database: " << ex.what();
1277 }
1278
1279 // Server will start DDNS communications if its enabled.
1280 try {
1281 srv->startD2();
1282 } catch (const std::exception& ex) {
1283 err << "Error starting DHCP_DDNS client after server reconfiguration: "
1284 << ex.what();
1286 }
1287
1288 // Setup DHCPv4-over-DHCPv6 IPC
1289 try {
1291 } catch (const std::exception& ex) {
1292 err << "error starting DHCPv4-over-DHCPv6 IPC "
1293 " after server reconfiguration: " << ex.what();
1295 }
1296
1297 // Configure DHCP packet queueing
1298 try {
1300 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
1301 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
1303 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
1304 }
1305
1306 } catch (const std::exception& ex) {
1307 err << "Error setting packet queue controls after server reconfiguration: "
1308 << ex.what();
1310 }
1311
1312 // Configure a callback to shut down the server when the bind socket
1313 // attempts exceeded.
1315 std::bind(&ControlledDhcpv4Srv::openSocketsFailedCallback, srv, ph::_1);
1316
1317 // Configuration may change active interfaces. Therefore, we have to reopen
1318 // sockets according to new configuration. It is possible that this
1319 // operation will fail for some interfaces but the openSockets function
1320 // guards against exceptions and invokes a callback function to
1321 // log warnings. Since we allow that this fails for some interfaces there
1322 // is no need to rollback configuration if socket fails to open on any
1323 // of the interfaces.
1324 CfgMgr::instance().getStagingCfg()->getCfgIface()->
1325 openSockets(AF_INET, srv->getServerPort(),
1327
1328 // Install the timers for handling leases reclamation.
1329 try {
1330 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
1331 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
1332 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
1333 server_);
1334
1335 } catch (const std::exception& ex) {
1336 err << "unable to setup timers for periodically running the"
1337 " reclamation of the expired leases: "
1338 << ex.what() << ".";
1340 }
1341
1342 // Setup config backend polling, if configured for it.
1343 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
1344 if (ctl_info) {
1345 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
1346 // Only schedule the CB fetch timer if the fetch wait time is greater
1347 // than 0.
1348 if (fetch_time > 0) {
1349 // When we run unit tests, we want to use milliseconds unit for the
1350 // specified interval. Otherwise, we use seconds. Note that using
1351 // milliseconds as a unit in unit tests prevents us from waiting 1
1352 // second on more before the timer goes off. Instead, we wait one
1353 // millisecond which significantly reduces the test time.
1354 if (!server_->inTestMode()) {
1355 fetch_time = 1000 * fetch_time;
1356 }
1357
1358 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1360 registerTimer("Dhcp4CBFetchTimer",
1361 std::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
1362 server_, CfgMgr::instance().getStagingCfg(),
1363 failure_count),
1364 fetch_time,
1366 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1367 }
1368 }
1369
1370 // Finally, we can commit runtime option definitions in libdhcp++. This is
1371 // exception free.
1373
1375 if (notify_libraries) {
1376 return (notify_libraries);
1377 }
1378
1379 // Initialize the allocators. If the user selected a Free Lease Queue Allocator
1380 // for any of the subnets, the server will now populate free leases to the queue.
1381 // It may take a while!
1382 try {
1383 CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->initAllocatorsAfterConfigure();
1384
1385 } catch (const std::exception& ex) {
1386 err << "Error initializing the lease allocators: "
1387 << ex.what();
1389 }
1390
1391 // Apply multi threading settings.
1392 // @note These settings are applied/updated only if no errors occur while
1393 // applying the new configuration.
1394 // @todo This should be fixed.
1395 try {
1396 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1397 } catch (const std::exception& ex) {
1398 err << "Error applying multi threading settings: "
1399 << ex.what();
1401 }
1402
1403 return (answer);
1404}
1405
1409 // This hook point notifies hooks libraries that the configuration of the
1410 // DHCPv4 server has completed. It provides the hook library with the pointer
1411 // to the common IO service object, new server configuration in the JSON
1412 // format and with the pointer to the configuration storage where the
1413 // parsed configuration is stored.
1414 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp4_srv_configured_)) {
1416
1417 callout_handle->setArgument("io_context", srv->getIOService());
1418 callout_handle->setArgument("network_state", srv->getNetworkState());
1419 callout_handle->setArgument("json_config", config);
1420 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1421
1422 HooksManager::callCallouts(Hooks.hooks_index_dhcp4_srv_configured_,
1423 *callout_handle);
1424
1425 // If next step is DROP, report a configuration error.
1426 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1427 string error;
1428 try {
1429 callout_handle->getArgument("error", error);
1430 } catch (NoSuchArgument const& ex) {
1431 error = "unknown error";
1432 }
1434 }
1435 }
1436
1437 return (ConstElementPtr());
1438}
1439
1443
1444 if (!srv) {
1446 "Server object not initialized, can't process config.");
1447 return (no_srv);
1448 }
1449
1451 .arg(srv->redactConfig(config)->str());
1452
1453 return (configureDhcp4Server(*srv, config, true));
1454}
1455
1456ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
1457 uint16_t client_port /*= 0*/)
1458 : Dhcpv4Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1459 if (getInstance()) {
1461 "There is another Dhcpv4Srv instance already.");
1462 }
1463 server_ = this; // remember this instance for later use in handlers
1464
1465 // ProcessSpawn uses IO service to handle signal set events.
1467
1468 // TimerMgr uses IO service to run asynchronous timers.
1469 TimerMgr::instance()->setIOService(getIOService());
1470
1471 // Command managers use IO service to run asynchronous socket operations.
1474
1475 // Set the HTTP authentication default realm.
1477
1478 // DatabaseConnection uses IO service to run asynchronous timers.
1480
1481 // These are the commands always supported by the DHCPv4 server.
1482 // Please keep the list in alphabetic order.
1483 CommandMgr::instance().registerCommand("build-report",
1484 std::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1485
1486 CommandMgr::instance().registerCommand("config-backend-pull",
1487 std::bind(&ControlledDhcpv4Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1488
1490 std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1491
1492 CommandMgr::instance().registerCommand("config-hash-get",
1493 std::bind(&ControlledDhcpv4Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1494
1495 CommandMgr::instance().registerCommand("config-reload",
1496 std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1497
1499 std::bind(&ControlledDhcpv4Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1500
1501 CommandMgr::instance().registerCommand("config-test",
1502 std::bind(&ControlledDhcpv4Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1503
1504 CommandMgr::instance().registerCommand("config-write",
1505 std::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1506
1507 CommandMgr::instance().registerCommand("dhcp-enable",
1508 std::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1509
1510 CommandMgr::instance().registerCommand("dhcp-disable",
1511 std::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1512
1513 CommandMgr::instance().registerCommand("leases-reclaim",
1514 std::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1515
1516 CommandMgr::instance().registerCommand("subnet4-select-test",
1517 std::bind(&ControlledDhcpv4Srv::commandSubnet4SelectTestHandler, this, ph::_1, ph::_2));
1518
1519 CommandMgr::instance().registerCommand("subnet4o6-select-test",
1520 std::bind(&ControlledDhcpv4Srv::commandSubnet4o6SelectTestHandler, this, ph::_1, ph::_2));
1521
1522 CommandMgr::instance().registerCommand("server-tag-get",
1523 std::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1524
1526 std::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1527
1529 std::bind(&ControlledDhcpv4Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1530
1531 CommandMgr::instance().registerCommand("version-get",
1532 std::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1533
1534 // Register statistic related commands
1535 CommandMgr::instance().registerCommand("statistic-get",
1536 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1537
1538 CommandMgr::instance().registerCommand("statistic-reset",
1539 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1540
1541 CommandMgr::instance().registerCommand("statistic-remove",
1542 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1543
1544 CommandMgr::instance().registerCommand("statistic-get-all",
1545 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1546
1547 CommandMgr::instance().registerCommand("statistic-reset-all",
1548 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1549
1550 CommandMgr::instance().registerCommand("statistic-remove-all",
1551 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1552
1553 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1554 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1555
1556 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1557 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1558
1559 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1560 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1561
1562 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1563 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1564}
1565
1567 setExitValue(exit_value);
1568 getIOService()->stop(); // Stop ASIO transmissions
1569 shutdown(); // Initiate DHCPv4 shutdown procedure.
1570}
1571
1573 try {
1574 MultiThreadingMgr::instance().apply(false, 0, 0);
1577
1578 // The closure captures either a shared pointer (memory leak)
1579 // or a raw pointer (pointing to a deleted object).
1583
1584 timer_mgr_->unregisterTimers();
1585
1586 cleanup();
1587
1588 // Close command sockets.
1591
1592 // Deregister any registered commands (please keep in alphabetic order)
1593 CommandMgr::instance().deregisterCommand("build-report");
1594 CommandMgr::instance().deregisterCommand("config-backend-pull");
1596 CommandMgr::instance().deregisterCommand("config-hash-get");
1597 CommandMgr::instance().deregisterCommand("config-reload");
1599 CommandMgr::instance().deregisterCommand("config-test");
1600 CommandMgr::instance().deregisterCommand("config-write");
1601 CommandMgr::instance().deregisterCommand("dhcp-disable");
1602 CommandMgr::instance().deregisterCommand("dhcp-enable");
1603 CommandMgr::instance().deregisterCommand("leases-reclaim");
1604 CommandMgr::instance().deregisterCommand("subnet4-select-test");
1605 CommandMgr::instance().deregisterCommand("subnet4o6-select-test");
1606 CommandMgr::instance().deregisterCommand("server-tag-get");
1608 CommandMgr::instance().deregisterCommand("statistic-get");
1609 CommandMgr::instance().deregisterCommand("statistic-get-all");
1610 CommandMgr::instance().deregisterCommand("statistic-remove");
1611 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1612 CommandMgr::instance().deregisterCommand("statistic-reset");
1613 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1614 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1615 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1616 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1617 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1619 CommandMgr::instance().deregisterCommand("version-get");
1620
1621 // Reset DatabaseConnection IO service.
1623 } catch (...) {
1624 // Don't want to throw exceptions from the destructor. The server
1625 // is shutting down anyway.
1626 }
1627
1628 server_ = NULL; // forget this instance. There should be no callback anymore
1629 // at this stage anyway.
1630}
1631
1632void
1633ControlledDhcpv4Srv::reclaimExpiredLeases(const size_t max_leases,
1634 const uint16_t timeout,
1635 const bool remove_lease,
1636 const uint16_t max_unwarned_cycles) {
1637 try {
1638 if (network_state_->isServiceEnabled()) {
1639 server_->alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
1640 remove_lease,
1641 max_unwarned_cycles);
1642 } else {
1644 .arg(CfgMgr::instance().getCurrentCfg()->
1645 getCfgExpiration()->getReclaimTimerWaitTime());
1646 }
1647 } catch (const std::exception& ex) {
1649 .arg(ex.what());
1650 }
1651 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1653}
1654
1655void
1656ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1657 if (network_state_->isServiceEnabled()) {
1658 server_->alloc_engine_->deleteExpiredReclaimedLeases4(secs);
1659 }
1660
1661 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1663}
1664
1665bool
1666ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1667 if (!db_reconnect_ctl) {
1668 // This should never happen
1670 return (false);
1671 }
1672
1673 // Disable service until the connection is recovered.
1674 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1675 db_reconnect_ctl->alterServiceState()) {
1676 network_state_->disableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1677 }
1678
1680 .arg(db_reconnect_ctl->id())
1681 .arg(db_reconnect_ctl->timerName());;
1682
1683 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1684 // return false.
1685 if (!db_reconnect_ctl->retriesLeft() ||
1686 !db_reconnect_ctl->retryInterval()) {
1688 .arg(db_reconnect_ctl->retriesLeft())
1689 .arg(db_reconnect_ctl->retryInterval())
1690 .arg(db_reconnect_ctl->id())
1691 .arg(db_reconnect_ctl->timerName());
1692 if (db_reconnect_ctl->exitOnFailure()) {
1693 shutdownServer(EXIT_FAILURE);
1694 }
1695 return (false);
1696 }
1697
1698 return (true);
1699}
1700
1701bool
1702ControlledDhcpv4Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1703 if (!db_reconnect_ctl) {
1704 // This should never happen
1706 return (false);
1707 }
1708
1709 // Enable service after the connection is recovered.
1710 if (db_reconnect_ctl->retriesLeft() != db_reconnect_ctl->maxRetries() &&
1711 db_reconnect_ctl->alterServiceState()) {
1712 network_state_->enableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1713 }
1714
1716 .arg(db_reconnect_ctl->id())
1717 .arg(db_reconnect_ctl->timerName());
1718
1719 db_reconnect_ctl->resetRetries();
1720
1721 return (true);
1722}
1723
1724bool
1725ControlledDhcpv4Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1726 if (!db_reconnect_ctl) {
1727 // This should never happen
1729 return (false);
1730 }
1731
1733 .arg(db_reconnect_ctl->maxRetries())
1734 .arg(db_reconnect_ctl->id())
1735 .arg(db_reconnect_ctl->timerName());
1736
1737 if (db_reconnect_ctl->exitOnFailure()) {
1738 shutdownServer(EXIT_FAILURE);
1739 }
1740
1741 return (true);
1742}
1743
1744void
1745ControlledDhcpv4Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1746 if (!reconnect_ctl) {
1747 // This should never happen
1749 return;
1750 }
1751
1753 .arg(reconnect_ctl->maxRetries());
1754
1755 if (reconnect_ctl->exitOnFailure()) {
1756 shutdownServer(EXIT_FAILURE);
1757 }
1758}
1759
1760void
1761ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1762 boost::shared_ptr<unsigned> failure_count) {
1763 // stop thread pool (if running)
1764 MultiThreadingCriticalSection cs;
1765
1766 try {
1767 // Fetch any configuration backend updates since our last fetch.
1768 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1769 CBControlDHCPv4::FetchMode::FETCH_UPDATE);
1770 (*failure_count) = 0;
1771
1772 } catch (const std::exception& ex) {
1774 .arg(ex.what());
1775
1776 // We allow at most 10 consecutive failures after which we stop
1777 // making further attempts to fetch the configuration updates.
1778 // Let's return without re-scheduling the timer.
1779 if (++(*failure_count) > 10) {
1782 return;
1783 }
1784 }
1785
1786 // Reschedule the timer to fetch new updates or re-try if
1787 // the previous attempt resulted in an error.
1788 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1789 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1790 }
1791}
1792
1793} // namespace dhcp
1794} // namespace isc
CtrlAgentHooks Hooks
@ map
Definition data.h:147
@ integer
Definition data.h:140
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())
Definition data.cc:249
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:304
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
static void setIOService(const isc::asiolink::IOServicePtr &io_service)
Sets IO service to be used by the database backends.
static DbCallback db_recovered_callback_
Optional callback function to invoke if an opened connection recovery succeeded.
static DbCallback db_failed_callback_
Optional callback function to invoke if an opened connection recovery failed.
static DbCallback db_lost_callback_
Optional callback function to invoke if an opened connection is lost.
void parse(std::string &access_string, isc::data::ConstElementPtr database_config)
Parse configuration value.
const DatabaseConnection::ParameterMap & getDbAccessParameters() const
Get database access parameters.
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:663
void shutdown() override
Instructs the server to shut down.
Definition dhcp4_srv.cc:770
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:54
static void destroy()
Destroy lease manager.
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:104
virtual size_t writeConfigFile(const std::string &config_file, isc::data::ConstElementPtr cfg=isc::data::ConstElementPtr()) const
Writes current configuration to specified file.
Definition daemon.cc:250
isc::asiolink::IOSignalSetPtr signal_set_
A pointer to the object installing custom signal handlers.
Definition daemon.h:266
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition daemon.h:272
void checkWriteConfigFile(std::string &file)
Checks the to-be-written configuration file name.
Definition daemon.cc:129
void setExitValue(int value)
Sets the exit value.
Definition daemon.h:236
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition daemon.cc:278
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.
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_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
@ error
Definition db_log.h:118
std::string getConfigReport()
Definition cfgrpt.cc:20
const isc::log::MessageID DHCP4_NOT_RUNNING
const isc::log::MessageID DHCP4_DYNAMIC_RECONFIGURATION_FAIL
const isc::log::MessageID DHCP4_CONFIG_RECEIVED
const isc::log::MessageID DHCP4_DYNAMIC_RECONFIGURATION_SUCCESS
boost::shared_ptr< 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:487
const isc::log::MessageID DHCP4_DB_RECONNECT_NO_DB_CTL
const isc::log::MessageID DHCP4_CB_PERIODIC_FETCH_UPDATES_RETRIES_EXHAUSTED
const isc::log::MessageID DHCP4_CONFIG_PACKET_QUEUE
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
const isc::log::MessageID DHCP4_CB_ON_DEMAND_FETCH_UPDATES_FAIL
const isc::log::MessageID DHCP4_CONFIG_LOAD_FAIL
const int DBG_DHCP4_COMMAND
Debug level used to log receiving commands.
Definition dhcp4_log.h:30
const isc::log::MessageID DHCP4_DB_RECONNECT_DISABLED
const isc::log::MessageID DHCP4_CONFIG_UNRECOVERABLE_ERROR
const int DBG_DHCP4_BASIC
Debug level used to trace basic operations within the code.
Definition dhcp4_log.h:33
const isc::log::MessageID DHCP4_DB_RECONNECT_SUCCEEDED
isc::data::ConstElementPtr configureDhcp4Server(Dhcpv4Srv &server, isc::data::ConstElementPtr config_set, bool check_only, bool extra_checks)
Configure DHCPv4 server (Dhcpv4Srv) with a set of configuration values.
const isc::log::MessageID DHCP4_MULTI_THREADING_INFO
const isc::log::MessageID DHCP4_OPEN_SOCKETS_NO_RECONNECT_CTL
const isc::log::MessageID DHCP4_RECLAIM_EXPIRED_LEASES_SKIPPED
isc::log::Logger dhcp4_logger(DHCP4_APP_LOGGER_NAME)
Base logger for DHCPv4 server.
Definition dhcp4_log.h:90
boost::shared_ptr< SharedNetwork4 > SharedNetwork4Ptr
Pointer to SharedNetwork4 object.
const isc::log::MessageID DHCP4_DB_RECONNECT_FAILED
const isc::log::MessageID DHCP4_OPEN_SOCKETS_FAILED
const isc::log::MessageID DHCP4_DYNAMIC_RECONFIGURATION
const isc::log::MessageID DHCP4_RECLAIM_EXPIRED_LEASES_FAIL
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
const isc::log::MessageID DHCP4_CONFIG_UNSUPPORTED_OBJECT
const isc::log::MessageID DHCP4_CB_PERIODIC_FETCH_UPDATES_FAIL
const isc::log::MessageID DHCP4_DB_RECONNECT_LOST_CONNECTION
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
long toSeconds(const StatsDuration &dur)
Returns the number of seconds in a duration.
Definition observation.h:49
void decodeFormattedHexString(const string &hex_string, vector< uint8_t > &binary)
Converts a formatted string of hexadecimal digits into a vector.
Definition str.cc:212
vector< uint8_t > quotedStringToBinary(const string &quoted_string)
Converts a string in quotes into vector.
Definition str.cc:139
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.
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.