Kea 2.7.5
ctrl_dhcp4_srv.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2024 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) {
82 CommandMgr::instance().processCommand(createCommand("config-reload"));
83 } else if ((signo == SIGTERM) || (signo == SIGINT)) {
84 CommandMgr::instance().processCommand(createCommand("shutdown"));
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.
182 CfgMgr::instance().rollback();
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
223 ControlledDhcpv4Srv::getInstance()->shutdownServer(exit_value);
224 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
225}
226
228ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
229 ConstElementPtr /*args*/) {
230 // Get configuration file name.
231 string file = ControlledDhcpv4Srv::getInstance()->getConfigFile();
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 }
294
295 if (filename.empty()) {
296 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
297 "Please specify filename explicitly."));
298 }
299
300 // Ok, it's time to write the file.
301 size_t size = 0;
302 try {
303 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
304 size = writeConfigFile(filename, cfg);
305 } catch (const isc::Exception& ex) {
306 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during config-write: ")
307 + ex.what()));
308 }
309 if (size == 0) {
310 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
311 + filename));
312 }
313
314 // Ok, it's time to return the successful response.
316 params->set("size", Element::create(static_cast<long long>(size)));
317 params->set("filename", Element::create(filename));
318
319 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
320 + filename + " successful", params));
321}
322
324ControlledDhcpv4Srv::commandConfigSetHandler(const string&,
325 ConstElementPtr args) {
326 const int status_code = CONTROL_RESULT_ERROR;
327 ConstElementPtr dhcp4;
328 string message;
329
330 // Command arguments are expected to be:
331 // { "Dhcp4": { ... } }
332 if (!args) {
333 message = "Missing mandatory 'arguments' parameter.";
334 } else {
335 dhcp4 = args->get("Dhcp4");
336 if (!dhcp4) {
337 message = "Missing mandatory 'Dhcp4' parameter.";
338 } else if (dhcp4->getType() != Element::map) {
339 message = "'Dhcp4' parameter expected to be a map.";
340 }
341 }
342
343 // Check unsupported objects.
344 if (message.empty()) {
345 for (auto const& obj : args->mapValue()) {
346 const string& obj_name = obj.first;
347 if (obj_name != "Dhcp4") {
349 .arg(obj_name);
350 if (message.empty()) {
351 message = "Unsupported '" + obj_name + "' parameter";
352 } else {
353 message += " (and '" + obj_name + "')";
354 }
355 }
356 }
357 if (!message.empty()) {
358 message += ".";
359 }
360 }
361
362 if (!message.empty()) {
363 // Something is amiss with arguments, return a failure response.
364 ConstElementPtr result = isc::config::createAnswer(status_code,
365 message);
366 return (result);
367 }
368
369 // stop thread pool (if running)
371
372 // We are starting the configuration process so we should remove any
373 // staging configuration that has been created during previous
374 // configuration attempts.
375 CfgMgr::instance().rollback();
376
377 // Parse the logger configuration explicitly into the staging config.
378 // Note this does not alter the current loggers, they remain in
379 // effect until we apply the logging config below. If no logging
380 // is supplied logging will revert to default logging.
381 Daemon::configureLogger(dhcp4, CfgMgr::instance().getStagingCfg());
382
383 // Let's apply the new logging. We do it early, so we'll be able to print
384 // out what exactly is wrong with the new config in case of problems.
385 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
386
387 // Now we configure the server proper.
388 ConstElementPtr result = processConfig(dhcp4);
389
390 // If the configuration parsed successfully, apply the new logger
391 // configuration and the commit the new configuration. We apply
392 // the logging first in case there's a configuration failure.
393 int rcode = 0;
394 isc::config::parseAnswer(rcode, result);
395 if (rcode == CONTROL_RESULT_SUCCESS) {
396 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
397
398 // Use new configuration.
399 CfgMgr::instance().commit();
400 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
401 // Ok, we applied the logging from the upcoming configuration, but
402 // there were problems with the config. As such, we need to back off
403 // and revert to the previous logging configuration. This is not done if
404 // sequence == 0, because that would mean always reverting to stdout by
405 // default, and it is arguably more helpful to have the error in a
406 // potential file or syslog configured in the upcoming configuration.
407 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
408
409 // Not initial configuration so someone can believe we reverted
410 // to the previous configuration. It is not the case so be clear
411 // about this.
413 }
414
416 try {
417 // Handle events registered by hooks using external IOService objects.
418 IOServiceMgr::instance().pollIOServices();
419 } catch (const std::exception& ex) {
420 std::ostringstream err;
421 err << "Error initializing hooks: "
422 << ex.what();
424 }
425
426 return (result);
427}
428
430ControlledDhcpv4Srv::commandConfigTestHandler(const string&,
431 ConstElementPtr args) {
432 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
433 ConstElementPtr dhcp4;
434 string message;
435
436 // Command arguments are expected to be:
437 // { "Dhcp4": { ... } }
438 if (!args) {
439 message = "Missing mandatory 'arguments' parameter.";
440 } else {
441 dhcp4 = args->get("Dhcp4");
442 if (!dhcp4) {
443 message = "Missing mandatory 'Dhcp4' parameter.";
444 } else if (dhcp4->getType() != Element::map) {
445 message = "'Dhcp4' parameter expected to be a map.";
446 }
447 }
448
449 // Check unsupported objects.
450 if (message.empty()) {
451 for (auto const& obj : args->mapValue()) {
452 const string& obj_name = obj.first;
453 if (obj_name != "Dhcp4") {
455 .arg(obj_name);
456 if (message.empty()) {
457 message = "Unsupported '" + obj_name + "' parameter";
458 } else {
459 message += " (and '" + obj_name + "')";
460 }
461 }
462 }
463 if (!message.empty()) {
464 message += ".";
465 }
466 }
467
468 if (!message.empty()) {
469 // Something is amiss with arguments, return a failure response.
470 ConstElementPtr result = isc::config::createAnswer(status_code,
471 message);
472 return (result);
473 }
474
475 // stop thread pool (if running)
477
478 // We are starting the configuration process so we should remove any
479 // staging configuration that has been created during previous
480 // configuration attempts.
481 CfgMgr::instance().rollback();
482
483 // Now we check the server proper.
484 return (checkConfig(dhcp4));
485}
486
488ControlledDhcpv4Srv::commandDhcpDisableHandler(const std::string&,
489 ConstElementPtr args) {
490 std::ostringstream message;
491 int64_t max_period = 0;
492 std::string origin;
493
494 // If the args map does not contain 'origin' parameter, the default type
495 // will be used (user command).
496 auto type = NetworkState::USER_COMMAND;
497
498 // Parse arguments to see if the 'max-period' or 'origin' parameters have
499 // been specified.
500 if (args) {
501 // Arguments must be a map.
502 if (args->getType() != Element::map) {
503 message << "arguments for the 'dhcp-disable' command must be a map";
504
505 } else {
506 ConstElementPtr max_period_element = args->get("max-period");
507 // max-period is optional.
508 if (max_period_element) {
509 // It must be an integer, if specified.
510 if (max_period_element->getType() != Element::integer) {
511 message << "'max-period' argument must be a number";
512
513 } else {
514 // It must be positive integer.
515 max_period = max_period_element->intValue();
516 if (max_period <= 0) {
517 message << "'max-period' must be positive integer";
518 }
519 }
520 }
521 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
522 // stable release. However, the 'origin' is kept for backward compatibility
523 // with Kea versions before 2.5.8. It is common to receive both parameters
524 // because HA hook library sends both in case the partner server hasn't been
525 // upgraded to the new version. The 'origin-id' takes precedence over the
526 // 'origin'.
527 ConstElementPtr origin_id_element = args->get("origin-id");
528 ConstElementPtr origin_element = args->get("origin");
529 // The 'origin-id' and 'origin' arguments are optional.
530 if (origin_id_element) {
531 if (origin_id_element->getType() == Element::integer) {
532 type = origin_id_element->intValue();
533 } else {
534 message << "'origin-id' argument must be a number";
535 }
536 } else if (origin_element) {
537 switch (origin_element->getType()) {
538 case Element::string:
539 origin = origin_element->stringValue();
540 if (origin == "ha-partner") {
542 } else if (origin != "user") {
543 if (origin.empty()) {
544 origin = "(empty string)";
545 }
546 message << "invalid value used for 'origin' parameter: "
547 << origin;
548 }
549 break;
550 case Element::integer:
551 type = origin_element->intValue();
552 break;
553 default:
554 // It must be a string or a number, if specified.
555 message << "'origin' argument must be a string or a number";
556 }
557 }
558 }
559 }
560
561 // No error occurred, so let's disable the service.
562 if (message.tellp() == 0) {
563 message << "DHCPv4 service disabled";
564 if (max_period > 0) {
565 message << " for " << max_period << " seconds";
566
567 // The user specified that the DHCP service should resume not
568 // later than in max-period seconds. If the 'dhcp-enable' command
569 // is not sent, the DHCP service will resume automatically.
570 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
571 type);
572 }
573 network_state_->disableService(type);
574
575 // Success.
576 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
577 }
578
579 // Failure.
580 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
581}
582
584ControlledDhcpv4Srv::commandDhcpEnableHandler(const std::string&,
585 ConstElementPtr args) {
586 std::ostringstream message;
587 std::string origin;
588
589 // If the args map does not contain 'origin' parameter, the default type
590 // will be used (user command).
591 auto type = NetworkState::USER_COMMAND;
592
593 // Parse arguments to see if the 'origin' parameter has been specified.
594 if (args) {
595 // Arguments must be a map.
596 if (args->getType() != Element::map) {
597 message << "arguments for the 'dhcp-enable' command must be a map";
598
599 } else {
600 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
601 // stable release. However, the 'origin' is kept for backward compatibility
602 // with Kea versions before 2.5.8. It is common to receive both parameters
603 // because HA hook library sends both in case the partner server hasn't been
604 // upgraded to the new version. The 'origin-id' takes precedence over the
605 // 'origin'.
606 ConstElementPtr origin_id_element = args->get("origin-id");
607 ConstElementPtr origin_element = args->get("origin");
608 // The 'origin-id' and 'origin' arguments are optional.
609 if (origin_id_element) {
610 if (origin_id_element->getType() == Element::integer) {
611 type = origin_id_element->intValue();
612 } else {
613 message << "'origin-id' argument must be a number";
614 }
615 } else if (origin_element) {
616 switch (origin_element->getType()) {
617 case Element::string:
618 origin = origin_element->stringValue();
619 if (origin == "ha-partner") {
621 } else if (origin != "user") {
622 if (origin.empty()) {
623 origin = "(empty string)";
624 }
625 message << "invalid value used for 'origin' parameter: "
626 << origin;
627 }
628 break;
629 case Element::integer:
630 type = origin_element->intValue();
631 break;
632 default:
633 // It must be a string or a number, if specified.
634 message << "'origin' argument must be a string or a number";
635 }
636 }
637 }
638 }
639
640 // No error occurred, so let's enable the service.
641 if (message.tellp() == 0) {
642 network_state_->enableService(type);
643
644 // Success.
646 "DHCP service successfully enabled"));
647 }
648
649 // Failure.
650 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
651}
652
654ControlledDhcpv4Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
656 ElementPtr arguments = Element::createMap();
657 arguments->set("extended", extended);
660 arguments);
661 return (answer);
662}
663
665ControlledDhcpv4Srv::commandBuildReportHandler(const string&,
667 ConstElementPtr answer =
669 return (answer);
670}
671
673ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
674 ConstElementPtr args) {
675 int status_code = CONTROL_RESULT_ERROR;
676 string message;
677
678 // args must be { "remove": <bool> }
679 if (!args) {
680 message = "Missing mandatory 'remove' parameter.";
681 } else {
682 ConstElementPtr remove_name = args->get("remove");
683 if (!remove_name) {
684 message = "Missing mandatory 'remove' parameter.";
685 } else if (remove_name->getType() != Element::boolean) {
686 message = "'remove' parameter expected to be a boolean.";
687 } else {
688 bool remove_lease = remove_name->boolValue();
689 server_->alloc_engine_->reclaimExpiredLeases4(0, 0, remove_lease);
690 status_code = 0;
691 message = "Reclamation of expired leases is complete.";
692 }
693 }
694 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
695 return (answer);
696}
697
699ControlledDhcpv4Srv::commandSubnet4SelectTestHandler(const string&,
700 ConstElementPtr args) {
701 if (!args) {
702 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
703 }
704 if (args->getType() != Element::map) {
705 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
706 }
707 bool ignore_link_sel =
708 CfgMgr::instance().getCurrentCfg()->getIgnoreRAILinkSelection();
709 SubnetSelector selector;
710 for (auto const& entry : args->mapValue()) {
711 ostringstream errmsg;
712 if (entry.first == "interface") {
713 if (entry.second->getType() != Element::string) {
714 errmsg << "'interface' entry must be a string";
715 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
716 }
717 selector.iface_name_ = entry.second->stringValue();
718 continue;
719 } else if (entry.first == "address") {
720 if (entry.second->getType() != Element::string) {
721 errmsg << "'address' entry must be a string";
722 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
723 }
724 try {
725 IOAddress addr(entry.second->stringValue());
726 if (!addr.isV4()) {
727 errmsg << "bad 'address' entry: not IPv4";
728 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
729 }
730 selector.ciaddr_ = addr;
731 continue;
732 } catch (const exception& ex) {
733 errmsg << "bad 'address' entry: " << ex.what();
734 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
735 }
736 } else if (entry.first == "relay") {
737 if (entry.second->getType() != Element::string) {
738 errmsg << "'relay' entry must be a string";
739 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
740 }
741 try {
742 IOAddress addr(entry.second->stringValue());
743 if (!addr.isV4()) {
744 errmsg << "bad 'relay' entry: not IPv4";
745 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
746 }
747 selector.giaddr_ = addr;
748 continue;
749 } catch (const exception& ex) {
750 errmsg << "bad 'relay' entry: " << ex.what();
751 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
752 }
753 } else if (entry.first == "local") {
754 if (entry.second->getType() != Element::string) {
755 errmsg << "'local' entry must be a string";
756 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
757 }
758 try {
759 IOAddress addr(entry.second->stringValue());
760 if (!addr.isV4()) {
761 errmsg << "bad 'local' entry: not IPv4";
762 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
763 }
764 selector.local_address_ = addr;
765 continue;
766 } catch (const exception& ex) {
767 errmsg << "bad 'local' entry: " << ex.what();
768 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
769 }
770 } else if (entry.first == "remote") {
771 if (entry.second->getType() != Element::string) {
772 errmsg << "'remote' entry must be a string";
773 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
774 }
775 try {
776 IOAddress addr(entry.second->stringValue());
777 if (!addr.isV4()) {
778 errmsg << "bad 'remote' entry: not IPv4";
779 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
780 }
781 selector.remote_address_ = addr;
782 continue;
783 } catch (const exception& ex) {
784 errmsg << "bad 'remote' entry: " << ex.what();
785 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
786 }
787 } else if (entry.first == "link") {
788 if (entry.second->getType() != Element::string) {
789 errmsg << "'link' entry must be a string";
790 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
791 }
792 try {
793 IOAddress addr(entry.second->stringValue());
794 if (!addr.isV4()) {
795 errmsg << "bad 'link' entry: not IPv4";
796 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
797 }
798 if (!ignore_link_sel) {
799 selector.option_select_ = addr;
800 }
801 continue;
802 } catch (const exception& ex) {
803 errmsg << "bad 'link' entry: " << ex.what();
804 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
805 }
806 } else if (entry.first == "subnet") {
807 // RAI link-selection has precedence over subnet-selection.
808 if (args->contains("link") && !ignore_link_sel) {
809 continue;
810 }
811 if (entry.second->getType() != Element::string) {
812 errmsg << "'subnet' entry must be a string";
813 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
814 }
815 try {
816 IOAddress addr(entry.second->stringValue());
817 if (!addr.isV4()) {
818 errmsg << "bad 'subnet' entry: not IPv4";
819 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
820 }
821 selector.option_select_ = addr;
822 continue;
823 } catch (const exception& ex) {
824 errmsg << "bad 'subnet' entry: " << ex.what();
825 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
826 }
827 } else if (entry.first == "classes") {
828 if (entry.second->getType() != Element::list) {
830 "'classes' entry must be a list"));
831 }
832 for (auto const& item : entry.second->listValue()) {
833 if (!item || (item->getType() != Element::string)) {
834 errmsg << "'classes' entry must be a list of strings";
835 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
836 }
837 // Skip empty client classes.
838 if (!item->stringValue().empty()) {
839 selector.client_classes_.insert(item->stringValue());
840 }
841 }
842 continue;
843 } else {
844 errmsg << "unknown entry '" << entry.first << "'";
845 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
846 }
847 }
848 ConstSubnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->
849 getCfgSubnets4()->selectSubnet(selector);
850 if (!subnet) {
851 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
852 }
853 SharedNetwork4Ptr network;
854 subnet->getSharedNetwork(network);
855 ostringstream msg;
856 if (network) {
857 msg << "selected shared network '" << network->getName()
858 << "' starting with subnet '" << subnet->toText()
859 << "' id " << subnet->getID();
860 } else {
861 msg << "selected subnet '" << subnet->toText()
862 << "' id " << subnet->getID();
863 }
864 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
865}
866
868ControlledDhcpv4Srv::commandSubnet4o6SelectTestHandler(const string&,
869 ConstElementPtr args) {
870 if (!args) {
871 return (createAnswer(CONTROL_RESULT_ERROR, "empty arguments"));
872 }
873 if (args->getType() != Element::map) {
874 return (createAnswer(CONTROL_RESULT_ERROR, "arguments must be a map"));
875 }
876 SubnetSelector selector;
877 selector.dhcp4o6_ = true;
878 selector.local_address_ = IOAddress::IPV6_ZERO_ADDRESS();
879 selector.remote_address_ = IOAddress::IPV6_ZERO_ADDRESS();
880 for (auto const& entry : args->mapValue()) {
881 ostringstream errmsg;
882 if (entry.first == "interface") {
883 if (entry.second->getType() != Element::string) {
884 errmsg << "'interface' entry must be a string";
885 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
886 }
887 selector.iface_name_ = entry.second->stringValue();
888 continue;
889 } if (entry.first == "interface-id") {
890 if (entry.second->getType() != Element::string) {
891 errmsg << "'interface-id' entry must be a string";
892 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
893 }
894 try {
895 string str = entry.second->stringValue();
896 vector<uint8_t> id = util::str::quotedStringToBinary(str);
897 if (id.empty()) {
899 }
900 if (id.empty()) {
901 errmsg << "'interface-id' must be not empty";
902 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
903 }
904 selector.interface_id_ = OptionPtr(new Option(Option::V6,
906 id));
907 continue;
908 } catch (...) {
909 errmsg << "value of 'interface-id' was not recognized";
910 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
911 }
912 } else if (entry.first == "address") {
913 if (entry.second->getType() != Element::string) {
914 errmsg << "'address' entry must be a string";
915 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
916 }
917 try {
918 IOAddress addr(entry.second->stringValue());
919 if (!addr.isV4()) {
920 errmsg << "bad 'address' entry: not IPv4";
921 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
922 }
923 selector.ciaddr_ = addr;
924 continue;
925 } catch (const exception& ex) {
926 errmsg << "bad 'address' entry: " << ex.what();
927 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
928 }
929 } else if (entry.first == "relay") {
930 if (entry.second->getType() != Element::string) {
931 errmsg << "'relay' entry must be a string";
932 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
933 }
934 try {
935 IOAddress addr(entry.second->stringValue());
936 if (!addr.isV4()) {
937 errmsg << "bad 'relay' entry: not IPv4";
938 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
939 }
940 selector.giaddr_ = addr;
941 continue;
942 } catch (const exception& ex) {
943 errmsg << "bad 'relay' entry: " << ex.what();
944 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
945 }
946 } else if (entry.first == "local") {
947 if (entry.second->getType() != Element::string) {
948 errmsg << "'local' entry must be a string";
949 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
950 }
951 try {
952 IOAddress addr(entry.second->stringValue());
953 if (!addr.isV6()) {
954 errmsg << "bad 'local' entry: not IPv6";
955 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
956 }
957 selector.local_address_ = addr;
958 continue;
959 } catch (const exception& ex) {
960 errmsg << "bad 'local' entry: " << ex.what();
961 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
962 }
963 } else if (entry.first == "remote") {
964 if (entry.second->getType() != Element::string) {
965 errmsg << "'remote' entry must be a string";
966 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
967 }
968 try {
969 IOAddress addr(entry.second->stringValue());
970 if (!addr.isV6()) {
971 errmsg << "bad 'remote' entry: not IPv6";
972 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
973 }
974 selector.remote_address_ = addr;
975 continue;
976 } catch (const exception& ex) {
977 errmsg << "bad 'remote' entry: " << ex.what();
978 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
979 }
980 } else if (entry.first == "link") {
981 if (entry.second->getType() != Element::string) {
982 errmsg << "'link' entry must be a string";
983 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
984 }
985 try {
986 IOAddress addr(entry.second->stringValue());
987 if (!addr.isV6()) {
988 errmsg << "bad 'link' entry: not IPv6";
989 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
990 }
991 selector.first_relay_linkaddr_ = addr;
992 continue;
993 } catch (const exception& ex) {
994 errmsg << "bad 'link' entry: " << ex.what();
995 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
996 }
997 } else if (entry.first == "subnet") {
998 if (entry.second->getType() != Element::string) {
999 errmsg << "'subnet' entry must be a string";
1000 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1001 }
1002 try {
1003 IOAddress addr(entry.second->stringValue());
1004 if (!addr.isV4()) {
1005 errmsg << "bad 'subnet' entry: not IPv4";
1006 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1007 }
1008 selector.option_select_ = addr;
1009 continue;
1010 } catch (const exception& ex) {
1011 errmsg << "bad 'subnet' entry: " << ex.what();
1012 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1013 }
1014 } else if (entry.first == "classes") {
1015 if (entry.second->getType() != Element::list) {
1017 "'classes' entry must be a list"));
1018 }
1019 for (auto const& item : entry.second->listValue()) {
1020 if (!item || (item->getType() != Element::string)) {
1021 errmsg << "'classes' entry must be a list of strings";
1022 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1023 }
1024 // Skip empty client classes.
1025 if (!item->stringValue().empty()) {
1026 selector.client_classes_.insert(item->stringValue());
1027 }
1028 }
1029 continue;
1030 } else {
1031 errmsg << "unknown entry '" << entry.first << "'";
1032 return (createAnswer(CONTROL_RESULT_ERROR, errmsg.str()));
1033 }
1034 }
1035 ConstSubnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->
1036 getCfgSubnets4()->selectSubnet4o6(selector);
1037 if (!subnet) {
1038 return (createAnswer(CONTROL_RESULT_EMPTY, "no subnet selected"));
1039 }
1040 SharedNetwork4Ptr network;
1041 subnet->getSharedNetwork(network);
1042 ostringstream msg;
1043 if (network) {
1044 msg << "selected shared network '" << network->getName()
1045 << "' starting with subnet '" << subnet->toText()
1046 << "' id " << subnet->getID();
1047 } else {
1048 msg << "selected subnet '" << subnet->toText()
1049 << "' id " << subnet->getID();
1050 }
1051 return (createAnswer(CONTROL_RESULT_SUCCESS, msg.str()));
1052}
1053
1055ControlledDhcpv4Srv::commandServerTagGetHandler(const std::string&,
1057 const std::string& tag =
1058 CfgMgr::instance().getCurrentCfg()->getServerTag();
1059 ElementPtr response = Element::createMap();
1060 response->set("server-tag", Element::create(tag));
1061
1062 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
1063}
1064
1066ControlledDhcpv4Srv::commandConfigBackendPullHandler(const std::string&,
1068 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
1069 if (!ctl_info) {
1070 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
1071 }
1072
1073 // stop thread pool (if running)
1075
1076 // Reschedule the periodic CB fetch.
1077 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1078 TimerMgr::instance()->cancel("Dhcp4CBFetchTimer");
1079 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1080 }
1081
1082 // Code from cbFetchUpdates.
1083 // The configuration to use is the current one because this is called
1084 // after the configuration manager commit.
1085 try {
1086 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
1088 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
1089 } catch (const std::exception& ex) {
1091 .arg(ex.what());
1093 "On demand configuration update failed: " +
1094 string(ex.what())));
1095 }
1097 "On demand configuration update successful."));
1098}
1099
1101ControlledDhcpv4Srv::commandStatusGetHandler(const string&,
1102 ConstElementPtr /*args*/) {
1103 ElementPtr status = Element::createMap();
1104 status->set("pid", Element::create(static_cast<int>(getpid())));
1105
1106 auto now = boost::posix_time::second_clock::universal_time();
1107 // Sanity check: start_ is always initialized.
1108 if (!start_.is_not_a_date_time()) {
1109 auto uptime = now - start_;
1110 status->set("uptime", Element::create(uptime.total_seconds()));
1111 }
1112
1113 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
1114 if (!last_commit.is_not_a_date_time()) {
1115 auto reload = now - last_commit;
1116 status->set("reload", Element::create(reload.total_seconds()));
1117 }
1118
1119 auto& mt_mgr = MultiThreadingMgr::instance();
1120 if (mt_mgr.getMode()) {
1121 status->set("multi-threading-enabled", Element::create(true));
1122 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
1123 MultiThreadingMgr::instance().getThreadPoolSize())));
1124 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
1125 MultiThreadingMgr::instance().getPacketQueueSize())));
1126 ElementPtr queue_stats = Element::createList();
1127 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
1128 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
1129 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
1130 status->set("packet-queue-statistics", queue_stats);
1131
1132 } else {
1133 status->set("multi-threading-enabled", Element::create(false));
1134 }
1135
1136 // Iterate through the interfaces and get all the errors.
1137 ElementPtr socket_errors(Element::createList());
1138 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
1139 for (std::string const& error : interface->getErrors()) {
1140 socket_errors->add(Element::create(error));
1141 }
1142 }
1143
1144 // Abstract the information from all sockets into a single status.
1145 ElementPtr sockets(Element::createMap());
1146 if (socket_errors->empty()) {
1147 sockets->set("status", Element::create("ready"));
1148 } else {
1149 ReconnectCtlPtr const reconnect_ctl(
1150 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
1151 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
1152 sockets->set("status", Element::create("retrying"));
1153 } else {
1154 sockets->set("status", Element::create("failed"));
1155 }
1156 sockets->set("errors", socket_errors);
1157 }
1158 status->set("sockets", sockets);
1159
1160 status->set("dhcp-state", network_state_->toElement());
1161
1162 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
1163}
1164
1166ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
1167 ConstElementPtr args) {
1168 StatsMgr& stats_mgr = StatsMgr::instance();
1169 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleCountAllHandler(args);
1170 // Update the default parameter.
1171 long max_samples = stats_mgr.getMaxSampleCountDefault();
1172 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1173 "statistic-default-sample-count", Element::create(max_samples));
1174 return (answer);
1175}
1176
1178ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
1179 ConstElementPtr args) {
1180 StatsMgr& stats_mgr = StatsMgr::instance();
1181 ConstElementPtr answer = stats_mgr.statisticSetMaxSampleAgeAllHandler(args);
1182 // Update the default parameter.
1183 auto duration = stats_mgr.getMaxSampleAgeDefault();
1184 long max_age = toSeconds(duration);
1185 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
1186 "statistic-default-sample-age", Element::create(max_age));
1187 return (answer);
1188}
1189
1193
1194 // Allow DB reconnect on startup. The database connection parameters specify
1195 // respective details.
1197
1198 // Single stream instance used in all error clauses
1199 std::ostringstream err;
1200
1201 if (!srv) {
1202 err << "Server object not initialized, can't process config.";
1204 }
1205
1207 .arg(srv->redactConfig(config)->str());
1208
1209 // Destroy lease manager before hooks unload.
1211
1212 // Destroy host manager before hooks unload.
1214
1215 ConstElementPtr answer = configureDhcp4Server(*srv, config);
1216
1217 // Check that configuration was successful. If not, do not reopen sockets
1218 // and don't bother with DDNS stuff.
1219 try {
1220 int rcode = 0;
1221 isc::config::parseAnswer(rcode, answer);
1222 if (rcode != 0) {
1223 return (answer);
1224 }
1225 } catch (const std::exception& ex) {
1226 err << "Failed to process configuration:" << ex.what();
1228 }
1229
1230 // Re-open lease and host database with new parameters.
1231 try {
1233 std::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, ph::_1);
1234
1236 std::bind(&ControlledDhcpv4Srv::dbRecoveredCallback, srv, ph::_1);
1237
1239 std::bind(&ControlledDhcpv4Srv::dbFailedCallback, srv, ph::_1);
1240
1241 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
1242 string params = "universe=4";
1243 cfg_db->setAppendedParameters(params);
1244 cfg_db->createManagers();
1245 // Reset counters related to connections as all managers have been recreated.
1246 srv->getNetworkState()->resetForDbConnection();
1247 srv->getNetworkState()->resetForLocalCommands();
1248 srv->getNetworkState()->resetForRemoteCommands();
1249 } catch (const std::exception& ex) {
1250 err << "Unable to open database: " << ex.what();
1252 }
1253
1254 // Server will start DDNS communications if its enabled.
1255 try {
1256 srv->startD2();
1257 } catch (const std::exception& ex) {
1258 err << "Error starting DHCP_DDNS client after server reconfiguration: "
1259 << ex.what();
1261 }
1262
1263 // Setup DHCPv4-over-DHCPv6 IPC
1264 try {
1265 Dhcp4to6Ipc::instance().open();
1266 } catch (const std::exception& ex) {
1267 err << "error starting DHCPv4-over-DHCPv6 IPC "
1268 " after server reconfiguration: " << ex.what();
1270 }
1271
1272 // Configure DHCP packet queueing
1273 try {
1275 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
1276 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
1278 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
1279 }
1280
1281 } catch (const std::exception& ex) {
1282 err << "Error setting packet queue controls after server reconfiguration: "
1283 << ex.what();
1285 }
1286
1287 // Configure a callback to shut down the server when the bind socket
1288 // attempts exceeded.
1290 std::bind(&ControlledDhcpv4Srv::openSocketsFailedCallback, srv, ph::_1);
1291
1292 // Configuration may change active interfaces. Therefore, we have to reopen
1293 // sockets according to new configuration. It is possible that this
1294 // operation will fail for some interfaces but the openSockets function
1295 // guards against exceptions and invokes a callback function to
1296 // log warnings. Since we allow that this fails for some interfaces there
1297 // is no need to rollback configuration if socket fails to open on any
1298 // of the interfaces.
1299 CfgMgr::instance().getStagingCfg()->getCfgIface()->
1300 openSockets(AF_INET, srv->getServerPort(),
1302
1303 // Install the timers for handling leases reclamation.
1304 try {
1305 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
1306 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
1307 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
1308 server_);
1309
1310 } catch (const std::exception& ex) {
1311 err << "unable to setup timers for periodically running the"
1312 " reclamation of the expired leases: "
1313 << ex.what() << ".";
1315 }
1316
1317 // Setup config backend polling, if configured for it.
1318 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
1319 if (ctl_info) {
1320 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
1321 // Only schedule the CB fetch timer if the fetch wait time is greater
1322 // than 0.
1323 if (fetch_time > 0) {
1324 // When we run unit tests, we want to use milliseconds unit for the
1325 // specified interval. Otherwise, we use seconds. Note that using
1326 // milliseconds as a unit in unit tests prevents us from waiting 1
1327 // second on more before the timer goes off. Instead, we wait one
1328 // millisecond which significantly reduces the test time.
1329 if (!server_->inTestMode()) {
1330 fetch_time = 1000 * fetch_time;
1331 }
1332
1333 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1335 registerTimer("Dhcp4CBFetchTimer",
1336 std::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
1337 server_, CfgMgr::instance().getStagingCfg(),
1338 failure_count),
1339 fetch_time,
1341 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1342 }
1343 }
1344
1345 // Finally, we can commit runtime option definitions in libdhcp++. This is
1346 // exception free.
1348
1349 auto notify_libraries = ControlledDhcpv4Srv::finishConfigHookLibraries(config);
1350 if (notify_libraries) {
1351 return (notify_libraries);
1352 }
1353
1354 // Initialize the allocators. If the user selected a Free Lease Queue Allocator
1355 // for any of the subnets, the server will now populate free leases to the queue.
1356 // It may take a while!
1357 try {
1358 CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->initAllocatorsAfterConfigure();
1359
1360 } catch (const std::exception& ex) {
1361 err << "Error initializing the lease allocators: "
1362 << ex.what();
1364 }
1365
1366 // Apply multi threading settings.
1367 // @note These settings are applied/updated only if no errors occur while
1368 // applying the new configuration.
1369 // @todo This should be fixed.
1370 try {
1371 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1372 } catch (const std::exception& ex) {
1373 err << "Error applying multi threading settings: "
1374 << ex.what();
1376 }
1377
1378 return (answer);
1379}
1380
1384 // This hook point notifies hooks libraries that the configuration of the
1385 // DHCPv4 server has completed. It provides the hook library with the pointer
1386 // to the common IO service object, new server configuration in the JSON
1387 // format and with the pointer to the configuration storage where the
1388 // parsed configuration is stored.
1389 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp4_srv_configured_)) {
1391
1392 callout_handle->setArgument("io_context", srv->getIOService());
1393 callout_handle->setArgument("network_state", srv->getNetworkState());
1394 callout_handle->setArgument("json_config", config);
1395 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1396
1397 HooksManager::callCallouts(Hooks.hooks_index_dhcp4_srv_configured_,
1398 *callout_handle);
1399
1400 // If next step is DROP, report a configuration error.
1401 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1402 string error;
1403 try {
1404 callout_handle->getArgument("error", error);
1405 } catch (NoSuchArgument const& ex) {
1406 error = "unknown error";
1407 }
1409 }
1410 }
1411
1412 return (ConstElementPtr());
1413}
1414
1418
1419 if (!srv) {
1421 "Server object not initialized, can't process config.");
1422 return (no_srv);
1423 }
1424
1426 .arg(srv->redactConfig(config)->str());
1427
1428 return (configureDhcp4Server(*srv, config, true));
1429}
1430
1431ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
1432 uint16_t client_port /*= 0*/)
1433 : Dhcpv4Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1434 if (getInstance()) {
1436 "There is another Dhcpv4Srv instance already.");
1437 }
1438 server_ = this; // remember this instance for later use in handlers
1439
1440 // ProcessSpawn uses IO service to handle signal set events.
1442
1443 // TimerMgr uses IO service to run asynchronous timers.
1444 TimerMgr::instance()->setIOService(getIOService());
1445
1446 // Command managers use IO service to run asynchronous socket operations.
1447 UnixCommandMgr::instance().setIOService(getIOService());
1448 HttpCommandMgr::instance().setIOService(getIOService());
1449
1450 // Set the HTTP authentication default realm.
1452
1453 // DatabaseConnection uses IO service to run asynchronous timers.
1455
1456 // These are the commands always supported by the DHCPv4 server.
1457 // Please keep the list in alphabetic order.
1458 CommandMgr::instance().registerCommand("build-report",
1459 std::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1460
1461 CommandMgr::instance().registerCommand("config-backend-pull",
1462 std::bind(&ControlledDhcpv4Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1463
1464 CommandMgr::instance().registerCommand("config-get",
1465 std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1466
1467 CommandMgr::instance().registerCommand("config-hash-get",
1468 std::bind(&ControlledDhcpv4Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1469
1470 CommandMgr::instance().registerCommand("config-reload",
1471 std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1472
1473 CommandMgr::instance().registerCommand("config-set",
1474 std::bind(&ControlledDhcpv4Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1475
1476 CommandMgr::instance().registerCommand("config-test",
1477 std::bind(&ControlledDhcpv4Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1478
1479 CommandMgr::instance().registerCommand("config-write",
1480 std::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1481
1482 CommandMgr::instance().registerCommand("dhcp-enable",
1483 std::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1484
1485 CommandMgr::instance().registerCommand("dhcp-disable",
1486 std::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1487
1488 CommandMgr::instance().registerCommand("leases-reclaim",
1489 std::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1490
1491 CommandMgr::instance().registerCommand("subnet4-select-test",
1492 std::bind(&ControlledDhcpv4Srv::commandSubnet4SelectTestHandler, this, ph::_1, ph::_2));
1493
1494 CommandMgr::instance().registerCommand("subnet4o6-select-test",
1495 std::bind(&ControlledDhcpv4Srv::commandSubnet4o6SelectTestHandler, this, ph::_1, ph::_2));
1496
1497 CommandMgr::instance().registerCommand("server-tag-get",
1498 std::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1499
1500 CommandMgr::instance().registerCommand("shutdown",
1501 std::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1502
1503 CommandMgr::instance().registerCommand("status-get",
1504 std::bind(&ControlledDhcpv4Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1505
1506 CommandMgr::instance().registerCommand("version-get",
1507 std::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1508
1509 // Register statistic related commands
1510 CommandMgr::instance().registerCommand("statistic-get",
1511 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1512
1513 CommandMgr::instance().registerCommand("statistic-reset",
1514 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1515
1516 CommandMgr::instance().registerCommand("statistic-remove",
1517 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1518
1519 CommandMgr::instance().registerCommand("statistic-get-all",
1520 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1521
1522 CommandMgr::instance().registerCommand("statistic-reset-all",
1523 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1524
1525 CommandMgr::instance().registerCommand("statistic-remove-all",
1526 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1527
1528 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1529 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1530
1531 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1532 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1533
1534 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1535 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1536
1537 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1538 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1539}
1540
1542 setExitValue(exit_value);
1543 getIOService()->stop(); // Stop ASIO transmissions
1544 shutdown(); // Initiate DHCPv4 shutdown procedure.
1545}
1546
1548 try {
1549 MultiThreadingMgr::instance().apply(false, 0, 0);
1552
1553 // The closure captures either a shared pointer (memory leak)
1554 // or a raw pointer (pointing to a deleted object).
1558
1559 timer_mgr_->unregisterTimers();
1560
1561 cleanup();
1562
1563 // Close command sockets.
1564 UnixCommandMgr::instance().closeCommandSocket();
1565 HttpCommandMgr::instance().close();
1566
1567 // Deregister any registered commands (please keep in alphabetic order)
1568 CommandMgr::instance().deregisterCommand("build-report");
1569 CommandMgr::instance().deregisterCommand("config-backend-pull");
1570 CommandMgr::instance().deregisterCommand("config-get");
1571 CommandMgr::instance().deregisterCommand("config-hash-get");
1572 CommandMgr::instance().deregisterCommand("config-reload");
1573 CommandMgr::instance().deregisterCommand("config-set");
1574 CommandMgr::instance().deregisterCommand("config-test");
1575 CommandMgr::instance().deregisterCommand("config-write");
1576 CommandMgr::instance().deregisterCommand("dhcp-disable");
1577 CommandMgr::instance().deregisterCommand("dhcp-enable");
1578 CommandMgr::instance().deregisterCommand("leases-reclaim");
1579 CommandMgr::instance().deregisterCommand("subnet4-select-test");
1580 CommandMgr::instance().deregisterCommand("subnet4o6-select-test");
1581 CommandMgr::instance().deregisterCommand("server-tag-get");
1582 CommandMgr::instance().deregisterCommand("shutdown");
1583 CommandMgr::instance().deregisterCommand("statistic-get");
1584 CommandMgr::instance().deregisterCommand("statistic-get-all");
1585 CommandMgr::instance().deregisterCommand("statistic-remove");
1586 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1587 CommandMgr::instance().deregisterCommand("statistic-reset");
1588 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1589 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1590 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1591 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1592 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1593 CommandMgr::instance().deregisterCommand("status-get");
1594 CommandMgr::instance().deregisterCommand("version-get");
1595
1596 // Reset DatabaseConnection IO service.
1598 } catch (...) {
1599 // Don't want to throw exceptions from the destructor. The server
1600 // is shutting down anyway.
1601 }
1602
1603 server_ = NULL; // forget this instance. There should be no callback anymore
1604 // at this stage anyway.
1605}
1606
1607void
1608ControlledDhcpv4Srv::reclaimExpiredLeases(const size_t max_leases,
1609 const uint16_t timeout,
1610 const bool remove_lease,
1611 const uint16_t max_unwarned_cycles) {
1612 try {
1613 server_->alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
1614 remove_lease,
1615 max_unwarned_cycles);
1616 } catch (const std::exception& ex) {
1618 .arg(ex.what());
1619 }
1620 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1622}
1623
1624void
1625ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1626 server_->alloc_engine_->deleteExpiredReclaimedLeases4(secs);
1627 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1629}
1630
1631bool
1632ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1633 if (!db_reconnect_ctl) {
1634 // This should never happen
1636 return (false);
1637 }
1638
1639 // Disable service until the connection is recovered.
1640 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1641 db_reconnect_ctl->alterServiceState()) {
1643 }
1644
1646
1647 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1648 // return false.
1649 if (!db_reconnect_ctl->retriesLeft() ||
1650 !db_reconnect_ctl->retryInterval()) {
1652 .arg(db_reconnect_ctl->retriesLeft())
1653 .arg(db_reconnect_ctl->retryInterval());
1654 if (db_reconnect_ctl->exitOnFailure()) {
1655 shutdownServer(EXIT_FAILURE);
1656 }
1657 return (false);
1658 }
1659
1660 return (true);
1661}
1662
1663bool
1664ControlledDhcpv4Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1665 if (!db_reconnect_ctl) {
1666 // This should never happen
1668 return (false);
1669 }
1670
1671 // Enable service after the connection is recovered.
1672 if (db_reconnect_ctl->alterServiceState()) {
1674 }
1675
1677
1678 db_reconnect_ctl->resetRetries();
1679
1680 return (true);
1681}
1682
1683bool
1684ControlledDhcpv4Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1685 if (!db_reconnect_ctl) {
1686 // This should never happen
1688 return (false);
1689 }
1690
1692 .arg(db_reconnect_ctl->maxRetries());
1693
1694 if (db_reconnect_ctl->exitOnFailure()) {
1695 shutdownServer(EXIT_FAILURE);
1696 }
1697
1698 return (true);
1699}
1700
1701void
1702ControlledDhcpv4Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1703 if (!reconnect_ctl) {
1704 // This should never happen
1706 return;
1707 }
1708
1710 .arg(reconnect_ctl->maxRetries());
1711
1712 if (reconnect_ctl->exitOnFailure()) {
1713 shutdownServer(EXIT_FAILURE);
1714 }
1715}
1716
1717void
1718ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1719 boost::shared_ptr<unsigned> failure_count) {
1720 // stop thread pool (if running)
1722
1723 try {
1724 // Fetch any configuration backend updates since our last fetch.
1725 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1727 (*failure_count) = 0;
1728
1729 } catch (const std::exception& ex) {
1731 .arg(ex.what());
1732
1733 // We allow at most 10 consecutive failures after which we stop
1734 // making further attempts to fetch the configuration updates.
1735 // Let's return without re-scheduling the timer.
1736 if (++(*failure_count) > 10) {
1739 return;
1740 }
1741 }
1742
1743 // Reschedule the timer to fetch new updates or re-try if
1744 // the previous attempt resulted in an error.
1745 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1746 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1747 }
1748}
1749
1750} // namespace dhcp
1751} // namespace isc
CtrlAgentHooks Hooks
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
static std::string getHash(const isc::data::ConstElementPtr &config)
returns a hash of a given Element structure
static CommandMgr & instance()
CommandMgr is a singleton class.
static std::string DEFAULT_AUTHENTICATION_REALM
Default HTTP authentication realm.
static HttpCommandMgr & instance()
HttpCommandMgr is a singleton class.
static UnixCommandMgr & instance()
UnixCommandMgr is a singleton class.
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:25
static void apply(data::ConstElementPtr value)
apply multi threading configuration
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.
DHCPv4 server service.
Definition dhcp4_srv.h:268
void shutdown() override
Instructs the server to shut down.
Definition dhcp4_srv.cc:769
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
Definition dhcp4_srv.h:319
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
static void create()
Creates new instance of the HostMgr.
Definition host_mgr.cc:52
Handles network interfaces, transmission and reception.
Definition iface_mgr.h:656
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:228
isc::asiolink::IOSignalSetPtr signal_set_
A pointer to the object installing custom signal handlers.
Definition daemon.h:257
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition daemon.h:263
void setExitValue(int value)
Sets the exit value.
Definition daemon.h:227
Statistics Manager class.
static StatsMgr & instance()
Statistics Manager accessor method.
RAII class creating a critical section.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
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.
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 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.
#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 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()
Creates a standard config/command level success answer message (i.e.
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
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 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
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.
Subnet selector used to specify parameters used to select a subnet.
bool dhcp4o6_
Specifies if the packet is DHCP4o6.
std::string iface_name_
Name of the interface on which the message was received.