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