Kea 2.2.0
ctrl_dhcp4_srv.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2022 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
10#include <cc/data.h>
12#include <config/command_mgr.h>
13#include <dhcp/libdhcp++.h>
15#include <dhcp4/dhcp4_log.h>
16#include <dhcp4/dhcp4to6_ipc.h>
21#include <dhcpsrv/cfgmgr.h>
22#include <dhcpsrv/db_type.h>
23#include <dhcpsrv/host_mgr.h>
25#include <hooks/hooks.h>
26#include <hooks/hooks_manager.h>
27#include <stats/stats_mgr.h>
29
30#include <signal.h>
31
32#include <sstream>
33
34using namespace isc::asiolink;
35using namespace isc::config;
36using namespace isc::data;
37using namespace isc::db;
38using namespace isc::dhcp;
39using namespace isc::hooks;
40using namespace isc::stats;
41using namespace isc::util;
42using namespace std;
43namespace ph = std::placeholders;
44
45namespace {
46
48struct CtrlDhcp4Hooks {
49 int hooks_index_dhcp4_srv_configured_;
50
52 CtrlDhcp4Hooks() {
53 hooks_index_dhcp4_srv_configured_ = HooksManager::registerHook("dhcp4_srv_configured");
54 }
55
56};
57
58// Declare a Hooks object. As this is outside any function or method, it
59// will be instantiated (and the constructor run) when the module is loaded.
60// As a result, the hook indexes will be defined before any method in this
61// module is called.
62CtrlDhcp4Hooks Hooks;
63
73void signalHandler(int signo) {
74 // SIGHUP signals a request to reconfigure the server.
75 if (signo == SIGHUP) {
76 ControlledDhcpv4Srv::processCommand("config-reload",
78 } else if ((signo == SIGTERM) || (signo == SIGINT)) {
79 ControlledDhcpv4Srv::processCommand("shutdown",
81 }
82}
83
84}
85
86namespace isc {
87namespace dhcp {
88
89ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = NULL;
90
91void
92ControlledDhcpv4Srv::init(const std::string& file_name) {
93 // Keep the call timestamp.
94 start_ = boost::posix_time::second_clock::universal_time();
95
96 // Configure the server using JSON file.
97 ConstElementPtr result = loadConfigFile(file_name);
98
99 int rcode;
100 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
101 if (rcode != CONTROL_RESULT_SUCCESS) {
102 string reason = comment ? comment->stringValue() :
103 "no details available";
104 isc_throw(isc::BadValue, reason);
105 }
106
107 // We don't need to call openActiveSockets() or startD2() as these
108 // methods are called in processConfig() which is called by
109 // processCommand("config-set", ...)
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 // Nothing to do here. No need to disconnect from anything.
123}
124
126ControlledDhcpv4Srv::loadConfigFile(const std::string& file_name) {
127 // This is a configuration backend implementation that reads the
128 // configuration from a JSON file.
129
132
133 // Basic sanity check: file name must not be empty.
134 try {
135 if (file_name.empty()) {
136 // Basic sanity check: file name must not be empty.
137 isc_throw(isc::BadValue, "JSON configuration file not specified."
138 " Please use -c command line option.");
139 }
140
141 // Read contents of the file and parse it as JSON
142 Parser4Context parser;
143 json = parser.parseFile(file_name, Parser4Context::PARSER_DHCP4);
144 if (!json) {
145 isc_throw(isc::BadValue, "no configuration found");
146 }
147
148 // Let's do sanity check before we call json->get() which
149 // works only for map.
150 if (json->getType() != isc::data::Element::map) {
151 isc_throw(isc::BadValue, "Configuration file is expected to be "
152 "a map, i.e., start with { and end with } and contain "
153 "at least an entry called 'Dhcp4' that itself is a map. "
154 << file_name
155 << " is a valid JSON, but its top element is not a map."
156 " Did you forget to add { } around your configuration?");
157 }
158
159 // Use parsed JSON structures to configure the server
160 result = ControlledDhcpv4Srv::processCommand("config-set", json);
161 if (!result) {
162 // Undetermined status of the configuration. This should never
163 // happen, but as the configureDhcp4Server returns a pointer, it is
164 // theoretically possible that it will return NULL.
165 isc_throw(isc::BadValue, "undefined result of "
166 "processCommand(\"config-set\", json)");
167 }
168
169 // Now check is the returned result is successful (rcode=0) or not
170 // (see @ref isc::config::parseAnswer).
171 int rcode;
172 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
173 if (rcode != CONTROL_RESULT_SUCCESS) {
174 string reason = comment ? comment->stringValue() :
175 "no details available";
176 isc_throw(isc::BadValue, reason);
177 }
178 } catch (const std::exception& ex) {
179 // If configuration failed at any stage, we drop the staging
180 // configuration and continue to use the previous one.
182
184 .arg(file_name).arg(ex.what());
185 isc_throw(isc::BadValue, "configuration error using file '"
186 << file_name << "': " << ex.what());
187 }
188
190 .arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
191 .arg(MultiThreadingMgr::instance().getThreadPoolSize())
192 .arg(MultiThreadingMgr::instance().getPacketQueueSize());
193
194 return (result);
195}
196
198ControlledDhcpv4Srv::commandShutdownHandler(const string&, ConstElementPtr args) {
201 return (createAnswer(CONTROL_RESULT_ERROR, "Shutdown failure."));
202 }
203
204 int exit_value = 0;
205 if (args) {
206 // @todo Should we go ahead and shutdown even if the args are invalid?
207 if (args->getType() != Element::map) {
208 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
209 }
210
211 ConstElementPtr param = args->get("exit-value");
212 if (param) {
213 if (param->getType() != Element::integer) {
215 "parameter 'exit-value' is not an integer"));
216 }
217
218 exit_value = param->intValue();
219 }
220 }
221
223 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
224}
225
227ControlledDhcpv4Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
228 // stop thread pool (if running)
230
231 // Clear the packet queue.
232 MultiThreadingMgr::instance().getThreadPool().reset();
233
234 try {
236 HookLibsCollection loaded = HooksManager::getLibraryInfo();
237 HooksManager::prepareUnloadLibraries();
238 static_cast<void>(HooksManager::unloadLibraries());
239 bool status = HooksManager::loadLibraries(loaded);
240 if (!status) {
241 isc_throw(Unexpected, "Failed to reload hooks libraries.");
242 }
243 } catch (const std::exception& ex) {
245 ConstElementPtr answer = isc::config::createAnswer(1, ex.what());
246 return (answer);
247 }
249 "Hooks libraries successfully reloaded.");
250 return (answer);
251}
252
254ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
255 ConstElementPtr /*args*/) {
256 // Get configuration file name.
257 std::string file = ControlledDhcpv4Srv::getInstance()->getConfigFile();
258 try {
260 auto result = loadConfigFile(file);
262 return (result);
263 } catch (const std::exception& ex) {
264 // Log the unsuccessful reconfiguration. The reason for failure
265 // should be already logged. Don't rethrow an exception so as
266 // the server keeps working.
268 .arg(file);
270 "Config reload failed: " + string(ex.what())));
271 }
272}
273
275ControlledDhcpv4Srv::commandConfigGetHandler(const string&,
276 ConstElementPtr /*args*/) {
277 ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
278
279 return (createAnswer(0, config));
280}
281
283ControlledDhcpv4Srv::commandConfigWriteHandler(const string&,
284 ConstElementPtr args) {
285 string filename;
286
287 if (args) {
288 if (args->getType() != Element::map) {
289 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
290 }
291 ConstElementPtr filename_param = args->get("filename");
292 if (filename_param) {
293 if (filename_param->getType() != Element::string) {
295 "passed parameter 'filename' is not a string"));
296 }
297 filename = filename_param->stringValue();
298 }
299 }
300
301 if (filename.empty()) {
302 // filename parameter was not specified, so let's use whatever we remember
303 // from the command-line
304 filename = getConfigFile();
305 }
306
307 if (filename.empty()) {
308 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
309 "Please specify filename explicitly."));
310 }
311
312 // Ok, it's time to write the file.
313 size_t size = 0;
314 try {
315 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
316 size = writeConfigFile(filename, cfg);
317 } catch (const isc::Exception& ex) {
318 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during write-config:")
319 + ex.what()));
320 }
321 if (size == 0) {
322 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
323 + filename));
324 }
325
326 // Ok, it's time to return the successful response.
328 params->set("size", Element::create(static_cast<long long>(size)));
329 params->set("filename", Element::create(filename));
330
331 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
332 + filename + " successful", params));
333}
334
336ControlledDhcpv4Srv::commandConfigSetHandler(const string&,
337 ConstElementPtr args) {
338 const int status_code = CONTROL_RESULT_ERROR;
339 ConstElementPtr dhcp4;
340 string message;
341
342 // Command arguments are expected to be:
343 // { "Dhcp4": { ... } }
344 if (!args) {
345 message = "Missing mandatory 'arguments' parameter.";
346 } else {
347 dhcp4 = args->get("Dhcp4");
348 if (!dhcp4) {
349 message = "Missing mandatory 'Dhcp4' parameter.";
350 } else if (dhcp4->getType() != Element::map) {
351 message = "'Dhcp4' parameter expected to be a map.";
352 }
353 }
354
355 // Check unsupported objects.
356 if (message.empty()) {
357 for (auto obj : args->mapValue()) {
358 const string& obj_name = obj.first;
359 if (obj_name != "Dhcp4") {
361 .arg(obj_name);
362 if (message.empty()) {
363 message = "Unsupported '" + obj_name + "' parameter";
364 } else {
365 message += " (and '" + obj_name + "')";
366 }
367 }
368 }
369 if (!message.empty()) {
370 message += ".";
371 }
372 }
373
374 if (!message.empty()) {
375 // Something is amiss with arguments, return a failure response.
376 ConstElementPtr result = isc::config::createAnswer(status_code,
377 message);
378 return (result);
379 }
380
381 // stop thread pool (if running)
383
384 // disable multi-threading (it will be applied by new configuration)
385 // this must be done in order to properly handle MT to ST transition
386 // when 'multi-threading' structure is missing from new config
387 MultiThreadingMgr::instance().apply(false, 0, 0);
388
389 // We are starting the configuration process so we should remove any
390 // staging configuration that has been created during previous
391 // configuration attempts.
393
394 // Parse the logger configuration explicitly into the staging config.
395 // Note this does not alter the current loggers, they remain in
396 // effect until we apply the logging config below. If no logging
397 // is supplied logging will revert to default logging.
398 Daemon::configureLogger(dhcp4, CfgMgr::instance().getStagingCfg());
399
400 // Let's apply the new logging. We do it early, so we'll be able to print
401 // out what exactly is wrong with the new config in case of problems.
402 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
403
404 // Now we configure the server proper.
405 ConstElementPtr result = processConfig(dhcp4);
406
407 // If the configuration parsed successfully, apply the new logger
408 // configuration and the commit the new configuration. We apply
409 // the logging first in case there's a configuration failure.
410 int rcode = 0;
411 isc::config::parseAnswer(rcode, result);
412 if (rcode == CONTROL_RESULT_SUCCESS) {
413 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
414
415 // Use new configuration.
417 } else {
418 // Ok, we applied the logging from the upcoming configuration, but
419 // there were problems with the config. As such, we need to back off
420 // and revert to the previous logging configuration.
421 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
422
423 if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
424 // Not initial configuration so someone can believe we reverted
425 // to the previous configuration. It is not the case so be clear
426 // about this.
428 }
429 }
430
431 return (result);
432}
433
435ControlledDhcpv4Srv::commandConfigTestHandler(const string&,
436 ConstElementPtr args) {
437 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
438 ConstElementPtr dhcp4;
439 string message;
440
441 // Command arguments are expected to be:
442 // { "Dhcp4": { ... } }
443 if (!args) {
444 message = "Missing mandatory 'arguments' parameter.";
445 } else {
446 dhcp4 = args->get("Dhcp4");
447 if (!dhcp4) {
448 message = "Missing mandatory 'Dhcp4' parameter.";
449 } else if (dhcp4->getType() != Element::map) {
450 message = "'Dhcp4' parameter expected to be a map.";
451 }
452 }
453
454 // Check unsupported objects.
455 if (message.empty()) {
456 for (auto obj : args->mapValue()) {
457 const string& obj_name = obj.first;
458 if (obj_name != "Dhcp4") {
460 .arg(obj_name);
461 if (message.empty()) {
462 message = "Unsupported '" + obj_name + "' parameter";
463 } else {
464 message += " (and '" + obj_name + "')";
465 }
466 }
467 }
468 if (!message.empty()) {
469 message += ".";
470 }
471 }
472
473 if (!message.empty()) {
474 // Something is amiss with arguments, return a failure response.
475 ConstElementPtr result = isc::config::createAnswer(status_code,
476 message);
477 return (result);
478 }
479
480 // stop thread pool (if running)
482
483 // We are starting the configuration process so we should remove any
484 // staging configuration that has been created during previous
485 // configuration attempts.
487
488 // Now we check the server proper.
489 return (checkConfig(dhcp4));
490}
491
493ControlledDhcpv4Srv::commandDhcpDisableHandler(const std::string&,
494 ConstElementPtr args) {
495 std::ostringstream message;
496 int64_t max_period = 0;
497 std::string origin;
498
499 // If the args map does not contain 'origin' parameter, the default type
500 // will be used (user command).
502
503 // Parse arguments to see if the 'max-period' or 'origin' parameters have
504 // been specified.
505 if (args) {
506 // Arguments must be a map.
507 if (args->getType() != Element::map) {
508 message << "arguments for the 'dhcp-disable' command must be a map";
509
510 } else {
511 ConstElementPtr max_period_element = args->get("max-period");
512 // max-period is optional.
513 if (max_period_element) {
514 // It must be an integer, if specified.
515 if (max_period_element->getType() != Element::integer) {
516 message << "'max-period' argument must be a number";
517
518 } else {
519 // It must be positive integer.
520 max_period = max_period_element->intValue();
521 if (max_period <= 0) {
522 message << "'max-period' must be positive integer";
523 }
524 }
525 }
526 ConstElementPtr origin_element = args->get("origin");
527 // The 'origin' parameter is optional.
528 if (origin_element) {
529 // It must be a string, if specified.
530 if (origin_element->getType() != Element::string) {
531 message << "'origin' argument must be a string";
532
533 } else {
534 origin = origin_element->stringValue();
535 if (origin == "ha-partner") {
537 } else if (origin != "user") {
538 if (origin.empty()) {
539 origin = "(empty string)";
540 }
541 message << "invalid value used for 'origin' parameter: "
542 << origin;
543 }
544 }
545 }
546 }
547 }
548
549 // No error occurred, so let's disable the service.
550 if (message.tellp() == 0) {
551 message << "DHCPv4 service disabled";
552 if (max_period > 0) {
553 message << " for " << max_period << " seconds";
554
555 // The user specified that the DHCP service should resume not
556 // later than in max-period seconds. If the 'dhcp-enable' command
557 // is not sent, the DHCP service will resume automatically.
558 network_state_->delayedEnableAll(static_cast<unsigned>(max_period),
559 type);
560 }
561 network_state_->disableService(type);
562
563 // Success.
564 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
565 }
566
567 // Failure.
568 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
569}
570
572ControlledDhcpv4Srv::commandDhcpEnableHandler(const std::string&,
573 ConstElementPtr args) {
574 std::ostringstream message;
575 std::string origin;
576
577 // If the args map does not contain 'origin' parameter, the default type
578 // will be used (user command).
580
581 // Parse arguments to see if the 'origin' parameter has been specified.
582 if (args) {
583 // Arguments must be a map.
584 if (args->getType() != Element::map) {
585 message << "arguments for the 'dhcp-enable' command must be a map";
586
587 } else {
588 ConstElementPtr origin_element = args->get("origin");
589 // The 'origin' parameter is optional.
590 if (origin_element) {
591 // It must be a string, if specified.
592 if (origin_element->getType() != Element::string) {
593 message << "'origin' argument must be a string";
594
595 } else {
596 origin = origin_element->stringValue();
597 if (origin == "ha-partner") {
599 } else if (origin != "user") {
600 if (origin.empty()) {
601 origin = "(empty string)";
602 }
603 message << "invalid value used for 'origin' parameter: "
604 << origin;
605 }
606 }
607 }
608 }
609 }
610
611 // No error occurred, so let's enable the service.
612 if (message.tellp() == 0) {
613 network_state_->enableService(type);
614
615 // Success.
617 "DHCP service successfully enabled"));
618 }
619
620 // Failure.
621 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
622}
623
625ControlledDhcpv4Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
627 ElementPtr arguments = Element::createMap();
628 arguments->set("extended", extended);
631 arguments);
632 return (answer);
633}
634
636ControlledDhcpv4Srv::commandBuildReportHandler(const string&,
638 ConstElementPtr answer =
640 return (answer);
641}
642
644ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
645 ConstElementPtr args) {
646 int status_code = CONTROL_RESULT_ERROR;
647 string message;
648
649 // args must be { "remove": <bool> }
650 if (!args) {
651 message = "Missing mandatory 'remove' parameter.";
652 } else {
653 ConstElementPtr remove_name = args->get("remove");
654 if (!remove_name) {
655 message = "Missing mandatory 'remove' parameter.";
656 } else if (remove_name->getType() != Element::boolean) {
657 message = "'remove' parameter expected to be a boolean.";
658 } else {
659 bool remove_lease = remove_name->boolValue();
660 server_->alloc_engine_->reclaimExpiredLeases4(0, 0, remove_lease);
661 status_code = 0;
662 message = "Reclamation of expired leases is complete.";
663 }
664 }
665 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
666 return (answer);
667}
668
670ControlledDhcpv4Srv::commandServerTagGetHandler(const std::string&,
672 const std::string& tag =
673 CfgMgr::instance().getCurrentCfg()->getServerTag();
674 ElementPtr response = Element::createMap();
675 response->set("server-tag", Element::create(tag));
676
677 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
678}
679
681ControlledDhcpv4Srv::commandConfigBackendPullHandler(const std::string&,
683 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
684 if (!ctl_info) {
685 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
686 }
687
688 // stop thread pool (if running)
690
691 // Reschedule the periodic CB fetch.
692 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
693 TimerMgr::instance()->cancel("Dhcp4CBFetchTimer");
694 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
695 }
696
697 // Code from cbFetchUpdates.
698 // The configuration to use is the current one because this is called
699 // after the configuration manager commit.
700 try {
701 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
702 auto mode = CBControlDHCPv4::FetchMode::FETCH_UPDATE;
703 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
704 } catch (const std::exception& ex) {
706 .arg(ex.what());
708 "On demand configuration update failed: " +
709 string(ex.what())));
710 }
712 "On demand configuration update successful."));
713}
714
716ControlledDhcpv4Srv::commandStatusGetHandler(const string&,
717 ConstElementPtr /*args*/) {
719 status->set("pid", Element::create(static_cast<int>(getpid())));
720
721 auto now = boost::posix_time::second_clock::universal_time();
722 // Sanity check: start_ is always initialized.
723 if (!start_.is_not_a_date_time()) {
724 auto uptime = now - start_;
725 status->set("uptime", Element::create(uptime.total_seconds()));
726 }
727
728 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
729 if (!last_commit.is_not_a_date_time()) {
730 auto reload = now - last_commit;
731 status->set("reload", Element::create(reload.total_seconds()));
732 }
733
734 auto& mt_mgr = MultiThreadingMgr::instance();
735 if (mt_mgr.getMode()) {
736 status->set("multi-threading-enabled", Element::create(true));
737 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
738 MultiThreadingMgr::instance().getThreadPoolSize())));
739 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
740 MultiThreadingMgr::instance().getPacketQueueSize())));
741 ElementPtr queue_stats = Element::createList();
742 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
743 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
744 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
745 status->set("packet-queue-statistics", queue_stats);
746
747 } else {
748 status->set("multi-threading-enabled", Element::create(false));
749 }
750
751 // Iterate through the interfaces and get all the errors.
752 ElementPtr socket_errors(Element::createList());
753 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
754 for (std::string const& error : interface->getErrors()) {
755 socket_errors->add(Element::create(error));
756 }
757 }
758
759 // Abstract the information from all sockets into a single status.
761 if (socket_errors->empty()) {
762 sockets->set("status", Element::create("ready"));
763 } else {
764 ReconnectCtlPtr const reconnect_ctl(
765 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
766 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
767 sockets->set("status", Element::create("retrying"));
768 } else {
769 sockets->set("status", Element::create("failed"));
770 }
771 sockets->set("errors", socket_errors);
772 }
773 status->set("sockets", sockets);
774
775 return (createAnswer(0, status));
776}
777
779ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
780 ConstElementPtr args) {
781 StatsMgr& stats_mgr = StatsMgr::instance();
783 // Update the default parameter.
784 long max_samples = stats_mgr.getMaxSampleCountDefault();
785 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
786 "statistic-default-sample-count", Element::create(max_samples));
787 return (answer);
788}
789
791ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
792 ConstElementPtr args) {
793 StatsMgr& stats_mgr = StatsMgr::instance();
795 // Update the default parameter.
796 auto duration = stats_mgr.getMaxSampleAgeDefault();
797 long max_age = toSeconds(duration);
798 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
799 "statistic-default-sample-age", Element::create(max_age));
800 return (answer);
801}
802
805 ConstElementPtr args) {
806 string txt = args ? args->str() : "(none)";
807
809 .arg(command).arg(txt);
810
812
813 if (!srv) {
815 "Server object not initialized, so can't process command '" +
816 command + "', arguments: '" + txt + "'.");
817 return (no_srv);
818 }
819
820 try {
821 if (command == "shutdown") {
822 return (srv->commandShutdownHandler(command, args));
823
824 } else if (command == "libreload") {
825 return (srv->commandLibReloadHandler(command, args));
826
827 } else if (command == "config-reload") {
828 return (srv->commandConfigReloadHandler(command, args));
829
830 } else if (command == "config-set") {
831 return (srv->commandConfigSetHandler(command, args));
832
833 } else if (command == "config-get") {
834 return (srv->commandConfigGetHandler(command, args));
835
836 } else if (command == "config-test") {
837 return (srv->commandConfigTestHandler(command, args));
838
839 } else if (command == "dhcp-disable") {
840 return (srv->commandDhcpDisableHandler(command, args));
841
842 } else if (command == "dhcp-enable") {
843 return (srv->commandDhcpEnableHandler(command, args));
844
845 } else if (command == "version-get") {
846 return (srv->commandVersionGetHandler(command, args));
847
848 } else if (command == "build-report") {
849 return (srv->commandBuildReportHandler(command, args));
850
851 } else if (command == "leases-reclaim") {
852 return (srv->commandLeasesReclaimHandler(command, args));
853
854 } else if (command == "config-write") {
855 return (srv->commandConfigWriteHandler(command, args));
856
857 } else if (command == "server-tag-get") {
858 return (srv->commandServerTagGetHandler(command, args));
859
860 } else if (command == "config-backend-pull") {
861 return (srv->commandConfigBackendPullHandler(command, args));
862
863 } else if (command == "status-get") {
864 return (srv->commandStatusGetHandler(command, args));
865 }
866
867 return (isc::config::createAnswer(1, "Unrecognized command:"
868 + command));
869
870 } catch (const isc::Exception& ex) {
871 return (isc::config::createAnswer(1, "Error while processing command '"
872 + command + "':" + ex.what() +
873 ", params: '" + txt + "'"));
874 }
875}
876
880
881 // Single stream instance used in all error clauses
882 std::ostringstream err;
883
884 if (!srv) {
885 err << "Server object not initialized, can't process config.";
886 return (isc::config::createAnswer(1, err.str()));
887 }
888
890 .arg(srv->redactConfig(config)->str());
891
892 ConstElementPtr answer = configureDhcp4Server(*srv, config);
893
894 // Check that configuration was successful. If not, do not reopen sockets
895 // and don't bother with DDNS stuff.
896 try {
897 int rcode = 0;
898 isc::config::parseAnswer(rcode, answer);
899 if (rcode != 0) {
900 return (answer);
901 }
902 } catch (const std::exception& ex) {
903 err << "Failed to process configuration:" << ex.what();
904 return (isc::config::createAnswer(1, err.str()));
905 }
906
907 // Re-open lease and host database with new parameters.
908 try {
910 std::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, ph::_1);
911
913 std::bind(&ControlledDhcpv4Srv::dbRecoveredCallback, srv, ph::_1);
914
916 std::bind(&ControlledDhcpv4Srv::dbFailedCallback, srv, ph::_1);
917
918 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
919 cfg_db->setAppendedParameters("universe=4");
920 cfg_db->createManagers();
921 // Reset counters related to connections as all managers have been recreated.
923 } catch (const std::exception& ex) {
924 err << "Unable to open database: " << ex.what();
925 return (isc::config::createAnswer(1, err.str()));
926 }
927
928 // Server will start DDNS communications if its enabled.
929 try {
930 srv->startD2();
931 } catch (const std::exception& ex) {
932 err << "Error starting DHCP_DDNS client after server reconfiguration: "
933 << ex.what();
934 return (isc::config::createAnswer(1, err.str()));
935 }
936
937 // Setup DHCPv4-over-DHCPv6 IPC
938 try {
940 } catch (const std::exception& ex) {
941 err << "error starting DHCPv4-over-DHCPv6 IPC "
942 " after server reconfiguration: " << ex.what();
943 return (isc::config::createAnswer(1, err.str()));
944 }
945
946 // Configure DHCP packet queueing
947 try {
949 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
950 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
952 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
953 }
954
955 } catch (const std::exception& ex) {
956 err << "Error setting packet queue controls after server reconfiguration: "
957 << ex.what();
958 return (isc::config::createAnswer(1, err.str()));
959 }
960
961 // Configure a callback to shut down the server when the bind socket
962 // attempts exceeded.
964 std::bind(&ControlledDhcpv4Srv::openSocketsFailedCallback, srv, ph::_1);
965
966 // Configuration may change active interfaces. Therefore, we have to reopen
967 // sockets according to new configuration. It is possible that this
968 // operation will fail for some interfaces but the openSockets function
969 // guards against exceptions and invokes a callback function to
970 // log warnings. Since we allow that this fails for some interfaces there
971 // is no need to rollback configuration if socket fails to open on any
972 // of the interfaces.
973 CfgMgr::instance().getStagingCfg()->getCfgIface()->
974 openSockets(AF_INET, srv->getServerPort(),
976
977 // Install the timers for handling leases reclamation.
978 try {
979 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
980 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
981 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
982 server_);
983
984 } catch (const std::exception& ex) {
985 err << "unable to setup timers for periodically running the"
986 " reclamation of the expired leases: "
987 << ex.what() << ".";
988 return (isc::config::createAnswer(1, err.str()));
989 }
990
991 // Setup config backend polling, if configured for it.
992 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
993 if (ctl_info) {
994 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
995 // Only schedule the CB fetch timer if the fetch wait time is greater
996 // than 0.
997 if (fetch_time > 0) {
998 // When we run unit tests, we want to use milliseconds unit for the
999 // specified interval. Otherwise, we use seconds. Note that using
1000 // milliseconds as a unit in unit tests prevents us from waiting 1
1001 // second on more before the timer goes off. Instead, we wait one
1002 // millisecond which significantly reduces the test time.
1003 if (!server_->inTestMode()) {
1004 fetch_time = 1000 * fetch_time;
1005 }
1006
1007 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1009 registerTimer("Dhcp4CBFetchTimer",
1010 std::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
1011 server_, CfgMgr::instance().getStagingCfg(),
1012 failure_count),
1013 fetch_time,
1015 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1016 }
1017 }
1018
1019 // Finally, we can commit runtime option definitions in libdhcp++. This is
1020 // exception free.
1022
1023 // This hook point notifies hooks libraries that the configuration of the
1024 // DHCPv4 server has completed. It provides the hook library with the pointer
1025 // to the common IO service object, new server configuration in the JSON
1026 // format and with the pointer to the configuration storage where the
1027 // parsed configuration is stored.
1028 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp4_srv_configured_)) {
1029 CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
1030
1031 callout_handle->setArgument("io_context", srv->getIOService());
1032 callout_handle->setArgument("network_state", srv->getNetworkState());
1033 callout_handle->setArgument("json_config", config);
1034 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1035
1036 HooksManager::callCallouts(Hooks.hooks_index_dhcp4_srv_configured_,
1037 *callout_handle);
1038
1039 // If next step is DROP, report a configuration error.
1040 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1041 string error;
1042 try {
1043 callout_handle->getArgument("error", error);
1044 } catch (NoSuchArgument const& ex) {
1045 error = "unknown error";
1046 }
1048 }
1049 }
1050
1051 // Apply multi threading settings.
1052 // @note These settings are applied/updated only if no errors occur while
1053 // applying the new configuration.
1054 // @todo This should be fixed.
1055 try {
1056 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1057 } catch (const std::exception& ex) {
1058 err << "Error applying multi threading settings: "
1059 << ex.what();
1061 }
1062
1063 return (answer);
1064}
1065
1068
1070 .arg(redactConfig(config)->str());
1071
1073
1074 // Single stream instance used in all error clauses
1075 std::ostringstream err;
1076
1077 if (!srv) {
1078 err << "Server object not initialized, can't process config.";
1079 return (isc::config::createAnswer(1, err.str()));
1080 }
1081
1082 return (configureDhcp4Server(*srv, config, true));
1083}
1084
1085ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
1086 uint16_t client_port /*= 0*/)
1087 : Dhcpv4Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1088 if (getInstance()) {
1090 "There is another Dhcpv4Srv instance already.");
1091 }
1092 server_ = this; // remember this instance for later use in handlers
1093
1094 // TimerMgr uses IO service to run asynchronous timers.
1095 TimerMgr::instance()->setIOService(getIOService());
1096
1097 // CommandMgr uses IO service to run asynchronous socket operations.
1098 CommandMgr::instance().setIOService(getIOService());
1099
1100 // LeaseMgr uses IO service to run asynchronous timers.
1102
1103 // HostMgr uses IO service to run asynchronous timers.
1105
1106 // These are the commands always supported by the DHCPv4 server.
1107 // Please keep the list in alphabetic order.
1108 CommandMgr::instance().registerCommand("build-report",
1109 std::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1110
1111 CommandMgr::instance().registerCommand("config-backend-pull",
1112 std::bind(&ControlledDhcpv4Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1113
1114 CommandMgr::instance().registerCommand("config-get",
1115 std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1116
1117 CommandMgr::instance().registerCommand("config-reload",
1118 std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1119
1120 CommandMgr::instance().registerCommand("config-set",
1121 std::bind(&ControlledDhcpv4Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1122
1123 CommandMgr::instance().registerCommand("config-test",
1124 std::bind(&ControlledDhcpv4Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1125
1126 CommandMgr::instance().registerCommand("config-write",
1127 std::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1128
1129 CommandMgr::instance().registerCommand("dhcp-enable",
1130 std::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1131
1132 CommandMgr::instance().registerCommand("dhcp-disable",
1133 std::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1134
1135 CommandMgr::instance().registerCommand("libreload",
1136 std::bind(&ControlledDhcpv4Srv::commandLibReloadHandler, this, ph::_1, ph::_2));
1137
1138 CommandMgr::instance().registerCommand("leases-reclaim",
1139 std::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1140
1141 CommandMgr::instance().registerCommand("server-tag-get",
1142 std::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1143
1144 CommandMgr::instance().registerCommand("shutdown",
1145 std::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1146
1147 CommandMgr::instance().registerCommand("status-get",
1148 std::bind(&ControlledDhcpv4Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1149
1150 CommandMgr::instance().registerCommand("version-get",
1151 std::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1152
1153 // Register statistic related commands
1154 CommandMgr::instance().registerCommand("statistic-get",
1155 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1156
1157 CommandMgr::instance().registerCommand("statistic-reset",
1158 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1159
1160 CommandMgr::instance().registerCommand("statistic-remove",
1161 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1162
1163 CommandMgr::instance().registerCommand("statistic-get-all",
1164 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1165
1166 CommandMgr::instance().registerCommand("statistic-reset-all",
1167 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1168
1169 CommandMgr::instance().registerCommand("statistic-remove-all",
1170 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1171
1172 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1173 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1174
1175 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1176 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1177
1178 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1179 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1180
1181 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1182 std::bind(&ControlledDhcpv4Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1183}
1184
1186 setExitValue(exit_value);
1187 getIOService()->stop(); // Stop ASIO transmissions
1188 shutdown(); // Initiate DHCPv4 shutdown procedure.
1189}
1190
1192 try {
1195 cleanup();
1196
1197 // The closure captures either a shared pointer (memory leak)
1198 // or a raw pointer (pointing to a deleted object).
1202
1203 timer_mgr_->unregisterTimers();
1204
1205 // Close the command socket (if it exists).
1206 CommandMgr::instance().closeCommandSocket();
1207
1208 // Deregister any registered commands (please keep in alphabetic order)
1209 CommandMgr::instance().deregisterCommand("build-report");
1210 CommandMgr::instance().deregisterCommand("config-backend-pull");
1211 CommandMgr::instance().deregisterCommand("config-get");
1212 CommandMgr::instance().deregisterCommand("config-reload");
1213 CommandMgr::instance().deregisterCommand("config-set");
1214 CommandMgr::instance().deregisterCommand("config-test");
1215 CommandMgr::instance().deregisterCommand("config-write");
1216 CommandMgr::instance().deregisterCommand("dhcp-disable");
1217 CommandMgr::instance().deregisterCommand("dhcp-enable");
1218 CommandMgr::instance().deregisterCommand("leases-reclaim");
1219 CommandMgr::instance().deregisterCommand("libreload");
1220 CommandMgr::instance().deregisterCommand("server-tag-get");
1221 CommandMgr::instance().deregisterCommand("shutdown");
1222 CommandMgr::instance().deregisterCommand("statistic-get");
1223 CommandMgr::instance().deregisterCommand("statistic-get-all");
1224 CommandMgr::instance().deregisterCommand("statistic-remove");
1225 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1226 CommandMgr::instance().deregisterCommand("statistic-reset");
1227 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1228 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1229 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1230 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1231 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1232 CommandMgr::instance().deregisterCommand("status-get");
1233 CommandMgr::instance().deregisterCommand("version-get");
1234
1235 // LeaseMgr uses IO service to run asynchronous timers.
1237
1238 // HostMgr uses IO service to run asynchronous timers.
1240 } catch (...) {
1241 // Don't want to throw exceptions from the destructor. The server
1242 // is shutting down anyway.
1243 ;
1244 }
1245
1246 server_ = NULL; // forget this instance. There should be no callback anymore
1247 // at this stage anyway.
1248}
1249
1250void
1251ControlledDhcpv4Srv::reclaimExpiredLeases(const size_t max_leases,
1252 const uint16_t timeout,
1253 const bool remove_lease,
1254 const uint16_t max_unwarned_cycles) {
1255 try {
1256 server_->alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
1257 remove_lease,
1258 max_unwarned_cycles);
1259 } catch (const std::exception& ex) {
1261 .arg(ex.what());
1262 }
1263 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1265}
1266
1267void
1268ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1269 server_->alloc_engine_->deleteExpiredReclaimedLeases4(secs);
1270 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1272}
1273
1274bool
1275ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1276 if (!db_reconnect_ctl) {
1277 // This should never happen
1279 return (false);
1280 }
1281
1282 // Disable service until the connection is recovered.
1283 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1284 db_reconnect_ctl->alterServiceState()) {
1286 }
1287
1289
1290 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1291 // return false.
1292 if (!db_reconnect_ctl->retriesLeft() ||
1293 !db_reconnect_ctl->retryInterval()) {
1295 .arg(db_reconnect_ctl->retriesLeft())
1296 .arg(db_reconnect_ctl->retryInterval());
1297 if (db_reconnect_ctl->exitOnFailure()) {
1298 shutdownServer(EXIT_FAILURE);
1299 }
1300 return (false);
1301 }
1302
1303 return (true);
1304}
1305
1306bool
1307ControlledDhcpv4Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1308 if (!db_reconnect_ctl) {
1309 // This should never happen
1311 return (false);
1312 }
1313
1314 // Enable service after the connection is recovered.
1315 if (db_reconnect_ctl->alterServiceState()) {
1317 }
1318
1320
1321 db_reconnect_ctl->resetRetries();
1322
1323 return (true);
1324}
1325
1326bool
1327ControlledDhcpv4Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1328 if (!db_reconnect_ctl) {
1329 // This should never happen
1331 return (false);
1332 }
1333
1335 .arg(db_reconnect_ctl->maxRetries());
1336
1337 if (db_reconnect_ctl->exitOnFailure()) {
1338 shutdownServer(EXIT_FAILURE);
1339 }
1340
1341 return (true);
1342}
1343
1344void
1345ControlledDhcpv4Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1346 if (!reconnect_ctl) {
1347 // This should never happen
1349 return;
1350 }
1351
1353 .arg(reconnect_ctl->maxRetries());
1354
1355 if (reconnect_ctl->exitOnFailure()) {
1356 shutdownServer(EXIT_FAILURE);
1357 }
1358}
1359
1360void
1361ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1362 boost::shared_ptr<unsigned> failure_count) {
1363 // stop thread pool (if running)
1365
1366 try {
1367 // Fetch any configuration backend updates since our last fetch.
1368 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1369 CBControlDHCPv4::FetchMode::FETCH_UPDATE);
1370 (*failure_count) = 0;
1371
1372 } catch (const std::exception& ex) {
1374 .arg(ex.what());
1375
1376 // We allow at most 10 consecutive failures after which we stop
1377 // making further attempts to fetch the configuration updates.
1378 // Let's return without re-scheduling the timer.
1379 if (++(*failure_count) > 10) {
1382 return;
1383 }
1384 }
1385
1386 // Reschedule the timer to fetch new updates or re-try if
1387 // the previous attempt resulted in an error.
1388 if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
1389 TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
1390 }
1391}
1392
1393} // namespace dhcp
1394} // 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 ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:241
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:291
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:286
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.
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
void rollback()
Removes staging configuration.
Definition: cfgmgr.cc:120
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition: cfgmgr.cc:167
void commit()
Commits the staging configuration.
Definition: cfgmgr.cc:90
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
static void apply(data::ConstElementPtr value)
apply multi threading configuration
Controlled version of the DHCPv4 server.
static isc::data::ConstElementPtr processConfig(isc::data::ConstElementPtr new_config)
Configuration processor.
virtual ~ControlledDhcpv4Srv()
Destructor.
isc::data::ConstElementPtr loadConfigFile(const std::string &file_name)
Configure DHCPv4 server using the configuration file specified.
void cleanup()
Performs cleanup, immediately before termination.
static isc::data::ConstElementPtr processCommand(const std::string &command, isc::data::ConstElementPtr args)
Command processor.
ControlledDhcpv4Srv(uint16_t server_port=DHCP4_SERVER_PORT, uint16_t client_port=0)
Constructor.
void init(const std::string &config_file)
Initializes the server.
static ControlledDhcpv4Srv * getInstance()
Returns pointer to the sole instance of Dhcpv4Srv.
void shutdownServer(int exit_value)
Initiates shutdown procedure for the whole DHCPv4 server.
isc::data::ConstElementPtr checkConfig(isc::data::ConstElementPtr new_config)
Configuration checker.
static Dhcp4to6Ipc & instance()
Returns pointer to the sole instance of Dhcp4to6Ipc.
Definition: dhcp4to6_ipc.cc:32
virtual void open()
Open communication socket.
Definition: dhcp4to6_ipc.cc:37
DHCPv4 server service.
Definition: dhcp4_srv.h:253
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
Definition: dhcp4_srv.cc:4171
void shutdown() override
Instructs the server to shut down.
Definition: dhcp4_srv.cc:729
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
Definition: dhcp4_srv.h:304
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
Definition: dhcp4_srv.h:1131
bool inTestMode() const
Checks if the server is running in unit test mode.
Definition: dhcp4_srv.h:299
NetworkStatePtr & getNetworkState()
Returns pointer to the network state used by the server.
Definition: dhcp4_srv.h:309
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
Definition: dhcp4_srv.cc:4207
bool useBroadcast() const
Return bool value indicating that broadcast flags should be set on sockets.
Definition: dhcp4_srv.h:419
NetworkStatePtr network_state_
Holds information about disabled DHCP service and/or disabled subnet/network scopes.
Definition: dhcp4_srv.h:1138
uint16_t getServerPort() const
Get UDP port on which server should listen.
Definition: dhcp4_srv.h:411
CBControlDHCPv4Ptr getCBControl() const
Returns an object which controls access to the configuration backends.
Definition: dhcp4_srv.h:318
static void setIOService(const isc::asiolink::IOServicePtr &io_service)
Sets IO service to be used by the Host Manager.
Definition: host_mgr.h:638
static void create()
Creates new instance of the HostMgr.
Definition: host_mgr.cc:43
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
static void destroy()
Destroy lease manager.
static void setIOService(const isc::asiolink::IOServicePtr &io_service)
Sets IO service to be used by the Lease Manager.
Definition: lease_mgr.h:786
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition: libdhcp++.cc:238
Origin
Origin of the network state transition.
Definition: network_state.h:84
@ USER_COMMAND
The network state is being altered by a user command.
@ DB_CONNECTION
The network state is being altered by the DB connection recovery mechanics.
@ HA_COMMAND
The network state is being altered by a HA internal command.
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:449
std::string getConfigFile() const
Returns config file name.
Definition: daemon.cc:105
virtual size_t writeConfigFile(const std::string &config_file, isc::data::ConstElementPtr cfg=isc::data::ConstElementPtr()) const
Writes current configuration to specified file.
Definition: daemon.cc:229
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
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition: daemon.cc:257
Statistics Manager class.
RAII class creating a critical section.
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.
#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.
isc::data::ConstElementPtr statisticSetMaxSampleAgeAllHandler(const isc::data::ConstElementPtr &params)
Handles statistic-sample-age-set-all 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 ...
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
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:27
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
@ error
Definition: db_log.h:115
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< 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
isc::data::ConstElementPtr configureDhcp4Server(Dhcpv4Srv &server, isc::data::ConstElementPtr config_set, bool check_only)
Configure DHCPv4 server (Dhcpv4Srv) with a set of configuration values.
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.
Definition: srv_config.h:1165
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_HOOKS_LIBS_RELOAD_FAIL
const isc::log::MessageID DHCP4_DB_RECONNECT_DISABLED
const isc::log::MessageID DHCP4_CONFIG_UNRECOVERABLE_ERROR
const isc::log::MessageID DHCP4_DB_RECONNECT_SUCCEEDED
const isc::log::MessageID DHCP4_COMMAND_RECEIVED
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
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
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
std::vector< HookLibInfo > HookLibsCollection
A storage for information about hook libraries.
Definition: libinfo.h:31
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:45
Definition: edns.h:19
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.