Kea 3.1.3
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 // Merge lease manager status.
1162 ElementPtr lm_info;
1165 }
1166 if (lm_info && (lm_info->getType() == Element::map)) {
1167 for (auto const& entry : lm_info->mapValue()) {
1168 status->set(entry.first, entry.second);
1169 }
1170 }
1171
1172 // Iterate through the interfaces and get all the errors.
1173 ElementPtr socket_errors(Element::createList());
1174 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
1175 for (std::string const& error : interface->getErrors()) {
1176 socket_errors->add(Element::create(error));
1177 }
1178 }
1179
1180 // Abstract the information from all sockets into a single status.
1181 ElementPtr sockets(Element::createMap());
1182 if (socket_errors->empty()) {
1183 sockets->set("status", Element::create("ready"));
1184 } else {
1185 ReconnectCtlPtr const reconnect_ctl(
1186 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
1187 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
1188 sockets->set("status", Element::create("retrying"));
1189 } else {
1190 sockets->set("status", Element::create("failed"));
1191 }
1192 sockets->set("errors", socket_errors);
1193 }
1194 status->set("sockets", sockets);
1195
1196 status->set("dhcp-state", network_state_->toElement());
1197
1198 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
1199}
1200
1202ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
1203 ConstElementPtr args) {
1204 StatsMgr& stats_mgr = StatsMgr::instance();
1206 // Update the default parameter.
1207 long max_samples = stats_mgr.getMaxSampleCountDefault();
1208 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1209 "statistic-default-sample-count", Element::create(max_samples));
1210 return (answer);
1211}
1212
1214ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
1215 ConstElementPtr args) {
1216 StatsMgr& stats_mgr = StatsMgr::instance();
1217 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleAgeAllHandler(args);
1218 // Update the default parameter.
1219 auto duration = stats_mgr.getMaxSampleAgeDefault();
1220 long max_age = toSeconds(duration);
1221 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1222 "statistic-default-sample-age", Element::create(max_age));
1223 return (answer);
1224}
1225
1227ControlledDhcpv4Srv::commandLfcStartHandler(const string&, ConstElementPtr) {
1229 return (LeaseMgrFactory::instance().lfcStartHandler());
1230 }
1232 "no lease backend"));
1233}
1234
1238
1239 // Allow DB reconnect on startup. The database connection parameters specify
1240 // respective details.
1242
1243 // Single stream instance used in all error clauses
1244 std::ostringstream err;
1245
1246 if (!srv) {
1247 err << "Server object not initialized, can't process config.";
1249 }
1250
1252 .arg(srv->redactConfig(config)->str());
1253
1254 // Destroy lease manager before hooks unload.
1256
1257 // Destroy host manager before hooks unload.
1259
1261
1262 // Check that configuration was successful. If not, do not reopen sockets
1263 // and don't bother with DDNS stuff.
1264 try {
1265 int rcode = 0;
1266 isc::config::parseAnswer(rcode, answer);
1267 if (rcode != 0) {
1268 return (answer);
1269 }
1270 } catch (const std::exception& ex) {
1271 err << "Failed to process configuration:" << ex.what();
1273 }
1274
1275 // Re-open lease and host database with new parameters.
1276 try {
1278 std::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, ph::_1);
1279
1281 std::bind(&ControlledDhcpv4Srv::dbRecoveredCallback, srv, ph::_1);
1282
1284 std::bind(&ControlledDhcpv4Srv::dbFailedCallback, srv, ph::_1);
1285
1286 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
1287 string params = "universe=4";
1288 cfg_db->setAppendedParameters(params);
1289 cfg_db->createManagers();
1290 // Reset counters related to connections as all managers have been recreated.
1291 srv->getNetworkState()->resetForDbConnection();
1292 srv->getNetworkState()->resetForLocalCommands();
1293 srv->getNetworkState()->resetForRemoteCommands();
1294 } catch (const std::exception& ex) {
1295 err << "Unable to open database: " << ex.what();
1297 }
1298
1299 // Server will start DDNS communications if its enabled.
1300 try {
1301 srv->startD2();
1302 } catch (const std::exception& ex) {
1303 err << "Error starting DHCP_DDNS client after server reconfiguration: "
1304 << ex.what();
1306 }
1307
1308 // Setup DHCPv4-over-DHCPv6 IPC
1309 try {
1311 } catch (const std::exception& ex) {
1312 err << "error starting DHCPv4-over-DHCPv6 IPC "
1313 " after server reconfiguration: " << ex.what();
1315 }
1316
1317 // Configure DHCP packet queueing
1318 try {
1320 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
1321 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
1323 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
1324 }
1325
1326 } catch (const std::exception& ex) {
1327 err << "Error setting packet queue controls after server reconfiguration: "
1328 << ex.what();
1330 }
1331
1332 // Configure a callback to shut down the server when the bind socket
1333 // attempts exceeded.
1335 std::bind(&ControlledDhcpv4Srv::openSocketsFailedCallback, srv, ph::_1);
1336
1337 // Configuration may change active interfaces. Therefore, we have to reopen
1338 // sockets according to new configuration. It is possible that this
1339 // operation will fail for some interfaces but the openSockets function
1340 // guards against exceptions and invokes a callback function to
1341 // log warnings. Since we allow that this fails for some interfaces there
1342 // is no need to rollback configuration if socket fails to open on any
1343 // of the interfaces.
1344 CfgMgr::instance().getStagingCfg()->getCfgIface()->
1345 openSockets(AF_INET, srv->getServerPort(),
1347
1348 // Install the timers for handling leases reclamation.
1349 try {
1350 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
1351 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
1352 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
1353 server_);
1354
1355 } catch (const std::exception& ex) {
1356 err << "unable to setup timers for periodically running the"
1357 " reclamation of the expired leases: "
1358 << ex.what() << ".";
1360 }
1361
1362 // Setup config backend polling, if configured for it.
1363 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
1364 if (ctl_info) {
1365 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
1366 // Only schedule the CB fetch timer if the fetch wait time is greater
1367 // than 0.
1368 if (fetch_time > 0) {
1369 // When we run unit tests, we want to use milliseconds unit for the
1370 // specified interval. Otherwise, we use seconds. Note that using
1371 // milliseconds as a unit in unit tests prevents us from waiting 1
1372 // second on more before the timer goes off. Instead, we wait one
1373 // millisecond which significantly reduces the test time.
1374 if (!server_->inTestMode()) {
1375 fetch_time = 1000 * fetch_time;
1376 }
1377
1378 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1380 registerTimer("Dhcp4CBFetchTimer",
1381 std::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
1382 server_, CfgMgr::instance().getStagingCfg(),
1383 failure_count),
1384 fetch_time,
1386 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1387 }
1388 }
1389
1390 // Finally, we can commit runtime option definitions in libdhcp++. This is
1391 // exception free.
1393
1395 if (notify_libraries) {
1396 return (notify_libraries);
1397 }
1398
1399 // Initialize the allocators. If the user selected a Free Lease Queue Allocator
1400 // for any of the subnets, the server will now populate free leases to the queue.
1401 // It may take a while!
1402 try {
1403 CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->initAllocatorsAfterConfigure();
1404
1405 } catch (const std::exception& ex) {
1406 err << "Error initializing the lease allocators: "
1407 << ex.what();
1409 }
1410
1411 // Apply multi threading settings.
1412 // @note These settings are applied/updated only if no errors occur while
1413 // applying the new configuration.
1414 // @todo This should be fixed.
1415 try {
1416 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1417 } catch (const std::exception& ex) {
1418 err << "Error applying multi threading settings: "
1419 << ex.what();
1421 }
1422
1423 return (answer);
1424}
1425
1429 // This hook point notifies hooks libraries that the configuration of the
1430 // DHCPv4 server has completed. It provides the hook library with the pointer
1431 // to the common IO service object, new server configuration in the JSON
1432 // format and with the pointer to the configuration storage where the
1433 // parsed configuration is stored.
1434 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp4_srv_configured_)) {
1436
1437 callout_handle->setArgument("io_context", srv->getIOService());
1438 callout_handle->setArgument("network_state", srv->getNetworkState());
1439 callout_handle->setArgument("json_config", config);
1440 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1441
1442 HooksManager::callCallouts(Hooks.hooks_index_dhcp4_srv_configured_,
1443 *callout_handle);
1444
1445 // If next step is DROP, report a configuration error.
1446 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1447 string error;
1448 try {
1449 callout_handle->getArgument("error", error);
1450 } catch (NoSuchArgument const& ex) {
1451 error = "unknown error";
1452 }
1454 }
1455 }
1456
1457 return (ConstElementPtr());
1458}
1459
1463
1464 if (!srv) {
1466 "Server object not initialized, can't process config.");
1467 return (no_srv);
1468 }
1469
1471 .arg(srv->redactConfig(config)->str());
1472
1473 return (configureDhcp4Server(*srv, config, true));
1474}
1475
1476ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
1477 uint16_t client_port /*= 0*/)
1478 : Dhcpv4Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1479 if (getInstance()) {
1481 "There is another Dhcpv4Srv instance already.");
1482 }
1483 server_ = this; // remember this instance for later use in handlers
1484
1485 // ProcessSpawn uses IO service to handle signal set events.
1487
1488 // TimerMgr uses IO service to run asynchronous timers.
1489 TimerMgr::instance()->setIOService(getIOService());
1490
1491 // Command managers use IO service to run asynchronous socket operations.
1494
1495 // Set the HTTP authentication default realm.
1497
1498 // DatabaseConnection uses IO service to run asynchronous timers.
1500
1501 // These are the commands always supported by the DHCPv4 server.
1502 // Please keep the list in alphabetic order.
1503 CommandMgr::instance().registerCommand("build-report",
1504 std::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1505
1506 CommandMgr::instance().registerCommand("config-backend-pull",
1507 std::bind(&ControlledDhcpv4Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1508
1510 std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1511
1512 CommandMgr::instance().registerCommand("config-hash-get",
1513 std::bind(&ControlledDhcpv4Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1514
1515 CommandMgr::instance().registerCommand("config-reload",
1516 std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1517
1519 std::bind(&ControlledDhcpv4Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1520
1521 CommandMgr::instance().registerCommand("config-test",
1522 std::bind(&ControlledDhcpv4Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1523
1524 CommandMgr::instance().registerCommand("config-write",
1525 std::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1526
1527 CommandMgr::instance().registerCommand("dhcp-enable",
1528 std::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1529
1530 CommandMgr::instance().registerCommand("dhcp-disable",
1531 std::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1532
1533 CommandMgr::instance().registerCommand("kea-lfc-start",
1534 std::bind(&ControlledDhcpv4Srv::commandLfcStartHandler, this, ph::_1, ph::_2));
1535
1536 CommandMgr::instance().registerCommand("leases-reclaim",
1537 std::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1538
1539 CommandMgr::instance().registerCommand("subnet4-select-test",
1540 std::bind(&ControlledDhcpv4Srv::commandSubnet4SelectTestHandler, this, ph::_1, ph::_2));
1541
1542 CommandMgr::instance().registerCommand("subnet4o6-select-test",
1543 std::bind(&ControlledDhcpv4Srv::commandSubnet4o6SelectTestHandler, this, ph::_1, ph::_2));
1544
1545 CommandMgr::instance().registerCommand("server-tag-get",
1546 std::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1547
1549 std::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1550
1552 std::bind(&ControlledDhcpv4Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1553
1554 CommandMgr::instance().registerCommand("version-get",
1555 std::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1556
1557 // Register statistic related commands
1558 CommandMgr::instance().registerCommand("statistic-get",
1559 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1560
1561 CommandMgr::instance().registerCommand("statistic-reset",
1562 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1563
1564 CommandMgr::instance().registerCommand("statistic-remove",
1565 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1566
1567 CommandMgr::instance().registerCommand("statistic-get-all",
1568 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1569
1570 CommandMgr::instance().registerCommand("statistic-global-get-all",
1571 std::bind(&StatsMgr::statisticGlobalGetAllHandler, ph::_1, ph::_2));
1572
1573 CommandMgr::instance().registerCommand("statistic-reset-all",
1574 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1575
1576 CommandMgr::instance().registerCommand("statistic-remove-all",
1577 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1578
1579 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1580 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1581
1582 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1583 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1584
1585 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1586 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1587
1588 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1589 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1590}
1591
1593 setExitValue(exit_value);
1594 getIOService()->stop(); // Stop ASIO transmissions
1595 shutdown(); // Initiate DHCPv4 shutdown procedure.
1596}
1597
1599 try {
1600 MultiThreadingMgr::instance().apply(false, 0, 0);
1603
1604 // The closure captures either a shared pointer (memory leak)
1605 // or a raw pointer (pointing to a deleted object).
1609
1610 timer_mgr_->unregisterTimers();
1611
1612 cleanup();
1613
1614 // Close command sockets.
1617
1618 // Deregister any registered commands (please keep in alphabetic order)
1619 CommandMgr::instance().deregisterCommand("build-report");
1620 CommandMgr::instance().deregisterCommand("config-backend-pull");
1622 CommandMgr::instance().deregisterCommand("config-hash-get");
1623 CommandMgr::instance().deregisterCommand("config-reload");
1625 CommandMgr::instance().deregisterCommand("config-test");
1626 CommandMgr::instance().deregisterCommand("config-write");
1627 CommandMgr::instance().deregisterCommand("dhcp-disable");
1628 CommandMgr::instance().deregisterCommand("dhcp-enable");
1629 CommandMgr::instance().deregisterCommand("kea-lfc-start");
1630 CommandMgr::instance().deregisterCommand("leases-reclaim");
1631 CommandMgr::instance().deregisterCommand("subnet4-select-test");
1632 CommandMgr::instance().deregisterCommand("subnet4o6-select-test");
1633 CommandMgr::instance().deregisterCommand("server-tag-get");
1635 CommandMgr::instance().deregisterCommand("statistic-get");
1636 CommandMgr::instance().deregisterCommand("statistic-get-all");
1637 CommandMgr::instance().deregisterCommand("statistic-global-get-all");
1638 CommandMgr::instance().deregisterCommand("statistic-remove");
1639 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1640 CommandMgr::instance().deregisterCommand("statistic-reset");
1641 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1642 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1643 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1644 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1645 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1647 CommandMgr::instance().deregisterCommand("version-get");
1648
1649 // Reset DatabaseConnection IO service.
1651 } catch (...) {
1652 // Don't want to throw exceptions from the destructor. The server
1653 // is shutting down anyway.
1654 }
1655
1656 server_ = NULL; // forget this instance. There should be no callback anymore
1657 // at this stage anyway.
1658}
1659
1660void
1661ControlledDhcpv4Srv::reclaimExpiredLeases(const size_t max_leases,
1662 const uint16_t timeout,
1663 const bool remove_lease,
1664 const uint16_t max_unwarned_cycles) {
1665 try {
1666 if (network_state_->isServiceEnabled()) {
1667 server_->alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
1668 remove_lease,
1669 max_unwarned_cycles);
1670 } else {
1672 .arg(CfgMgr::instance().getCurrentCfg()->
1673 getCfgExpiration()->getReclaimTimerWaitTime());
1674 }
1675 } catch (const std::exception& ex) {
1677 .arg(ex.what());
1678 }
1679 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1681}
1682
1683void
1684ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1685 if (network_state_->isServiceEnabled()) {
1686 server_->alloc_engine_->deleteExpiredReclaimedLeases4(secs);
1687 }
1688
1689 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1691}
1692
1693bool
1694ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1695 if (!db_reconnect_ctl) {
1696 // This should never happen
1698 return (false);
1699 }
1700
1701 // Disable service until the connection is recovered.
1702 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1703 db_reconnect_ctl->alterServiceState()) {
1704 network_state_->disableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1705 }
1706
1708 .arg(db_reconnect_ctl->id())
1709 .arg(db_reconnect_ctl->timerName());;
1710
1711 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1712 // return false.
1713 if (!db_reconnect_ctl->retriesLeft() ||
1714 !db_reconnect_ctl->retryInterval()) {
1716 .arg(db_reconnect_ctl->retriesLeft())
1717 .arg(db_reconnect_ctl->retryInterval())
1718 .arg(db_reconnect_ctl->id())
1719 .arg(db_reconnect_ctl->timerName());
1720 if (db_reconnect_ctl->exitOnFailure()) {
1721 shutdownServer(EXIT_FAILURE);
1722 }
1723 return (false);
1724 }
1725
1726 return (true);
1727}
1728
1729bool
1730ControlledDhcpv4Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1731 if (!db_reconnect_ctl) {
1732 // This should never happen
1734 return (false);
1735 }
1736
1737 // Enable service after the connection is recovered.
1738 if (db_reconnect_ctl->retriesLeft() != db_reconnect_ctl->maxRetries() &&
1739 db_reconnect_ctl->alterServiceState()) {
1740 network_state_->enableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1741 }
1742
1744 .arg(db_reconnect_ctl->id())
1745 .arg(db_reconnect_ctl->timerName());
1746
1747 db_reconnect_ctl->resetRetries();
1748
1749 return (true);
1750}
1751
1752bool
1753ControlledDhcpv4Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1754 if (!db_reconnect_ctl) {
1755 // This should never happen
1757 return (false);
1758 }
1759
1761 .arg(db_reconnect_ctl->maxRetries())
1762 .arg(db_reconnect_ctl->id())
1763 .arg(db_reconnect_ctl->timerName());
1764
1765 if (db_reconnect_ctl->exitOnFailure()) {
1766 shutdownServer(EXIT_FAILURE);
1767 }
1768
1769 return (true);
1770}
1771
1772void
1773ControlledDhcpv4Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1774 if (!reconnect_ctl) {
1775 // This should never happen
1777 return;
1778 }
1779
1781 .arg(reconnect_ctl->maxRetries());
1782
1783 if (reconnect_ctl->exitOnFailure()) {
1784 shutdownServer(EXIT_FAILURE);
1785 }
1786}
1787
1788void
1789ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1790 boost::shared_ptr<unsigned> failure_count) {
1791 // stop thread pool (if running)
1792 MultiThreadingCriticalSection cs;
1793
1794 try {
1795 // Fetch any configuration backend updates since our last fetch.
1796 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1797 CBControlDHCPv4::FetchMode::FETCH_UPDATE);
1798 (*failure_count) = 0;
1799
1800 } catch (const std::exception& ex) {
1802 .arg(ex.what());
1803
1804 // We allow at most 10 consecutive failures after which we stop
1805 // making further attempts to fetch the configuration updates.
1806 // Let's return without re-scheduling the timer.
1807 if (++(*failure_count) > 10) {
1810 return;
1811 }
1812 }
1813
1814 // Reschedule the timer to fetch new updates or re-try if
1815 // the previous attempt resulted in an error.
1816 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1817 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1818 }
1819}
1820
1821} // namespace dhcp
1822} // 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:664
void shutdown() override
Instructs the server to shut down.
Definition dhcp4_srv.cc:771
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 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:105
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:267
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:130
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:295
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: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.