Kea 2.5.8
dhcp6/json_config_parser.cc
Go to the documentation of this file.
1// Copyright (C) 2012-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
11#include <cc/data.h>
13#include <config/command_mgr.h>
16#include <dhcp6/dhcp6_log.h>
17#include <dhcp6/dhcp6_srv.h>
19#include <dhcp/libdhcp++.h>
20#include <dhcp/iface_mgr.h>
23#include <dhcpsrv/cfg_option.h>
24#include <dhcpsrv/cfgmgr.h>
25#include <dhcpsrv/db_type.h>
40#include <dhcpsrv/pool.h>
41#include <dhcpsrv/subnet.h>
42#include <dhcpsrv/timer_mgr.h>
43#include <hooks/hooks_manager.h>
44#include <hooks/hooks_parser.h>
45#include <log/logger_support.h>
47#include <util/encode/encode.h>
49#include <util/triplet.h>
50
51#include <boost/algorithm/string.hpp>
52#include <boost/lexical_cast.hpp>
53#include <boost/scoped_ptr.hpp>
54#include <boost/shared_ptr.hpp>
55
56#include <iostream>
57#include <limits>
58#include <map>
59#include <netinet/in.h>
60#include <vector>
61
62#include <stdint.h>
63
64using namespace std;
65using namespace isc;
66using namespace isc::data;
67using namespace isc::dhcp;
68using namespace isc::asiolink;
69using namespace isc::hooks;
70using namespace isc::process;
71using namespace isc::config;
72using namespace isc::util;
73
74namespace {
75
80void dirExists(const string& dir_path) {
81 struct stat statbuf;
82 if (stat(dir_path.c_str(), &statbuf) < 0) {
83 isc_throw(BadValue, "Bad directory '" << dir_path
84 << "': " << strerror(errno));
85 }
86 if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
87 isc_throw(BadValue, "'" << dir_path << "' is not a directory");
88 }
89}
90
99class RSOOListConfigParser : public isc::data::SimpleParser {
100public:
101
109 void parse(const SrvConfigPtr& cfg, const isc::data::ConstElementPtr& value) {
110 try {
111 for (auto const& source_elem : value->listValue()) {
112 std::string option_str = source_elem->stringValue();
113 // This option can be either code (integer) or name. Let's try code first
114 int64_t code = 0;
115 try {
116 code = boost::lexical_cast<int64_t>(option_str);
117 // Protect against the negative value and too high value.
118 if (code < 0) {
119 isc_throw(BadValue, "invalid option code value specified '"
120 << option_str << "', the option code must be a"
121 " non-negative value");
122
123 } else if (code > std::numeric_limits<uint16_t>::max()) {
124 isc_throw(BadValue, "invalid option code value specified '"
125 << option_str << "', the option code must not be"
126 " greater than '" << std::numeric_limits<uint16_t>::max()
127 << "'");
128 }
129
130 } catch (const boost::bad_lexical_cast &) {
131 // Oh well, it's not a number
132 }
133
134 if (!code) {
136 option_str);
137 if (def) {
138 code = def->getCode();
139 } else {
140 isc_throw(BadValue, "unable to find option code for the "
141 " specified option name '" << option_str << "'"
142 " while parsing the list of enabled"
143 " relay-supplied-options");
144 }
145 }
146 cfg->getCfgRSOO()->enable(code);
147 }
148 } catch (const std::exception& ex) {
149 // Rethrow exception with the appended position of the parsed
150 // element.
151 isc_throw(DhcpConfigError, ex.what() << " (" << value->getPosition() << ")");
152 }
153 }
154};
155
164class Dhcp6ConfigParser : public isc::data::SimpleParser {
165public:
166
181 void parse(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
182
183 // Set the data directory for server id file.
184 if (global->contains("data-directory")) {
185 CfgMgr::instance().setDataDir(getString(global, "data-directory"),
186 false);
187 }
188
189 // Set the probation period for decline handling.
190 uint32_t probation_period =
191 getUint32(global, "decline-probation-period");
192 cfg->setDeclinePeriod(probation_period);
193
194 // Set the DHCPv4-over-DHCPv6 interserver port.
195 uint16_t dhcp4o6_port = getUint16(global, "dhcp4o6-port");
196 cfg->setDhcp4o6Port(dhcp4o6_port);
197
198 // Set the global user context.
199 ConstElementPtr user_context = global->get("user-context");
200 if (user_context) {
201 cfg->setContext(user_context);
202 }
203
204 // Set the server's logical name
205 std::string server_tag = getString(global, "server-tag");
206 cfg->setServerTag(server_tag);
207 }
208
220 void parseEarly(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
221 // Set ip-reservations-unique flag.
222 bool ip_reservations_unique = getBoolean(global, "ip-reservations-unique");
223 cfg->setIPReservationsUnique(ip_reservations_unique);
224 }
225
232 void
233 copySubnets6(const CfgSubnets6Ptr& dest, const CfgSharedNetworks6Ptr& from) {
234
235 if (!dest || !from) {
236 isc_throw(BadValue, "Unable to copy subnets: at least one pointer is null");
237 }
238
239 const SharedNetwork6Collection* networks = from->getAll();
240 if (!networks) {
241 // Nothing to copy. Technically, it should return a pointer to empty
242 // container, but let's handle null pointer as well.
243 return;
244 }
245
246 // Let's go through all the networks one by one
247 for (auto const& net : *networks) {
248
249 // For each network go through all the subnets in it.
250 const Subnet6SimpleCollection* subnets = net->getAllSubnets();
251 if (!subnets) {
252 // Shared network without subnets it weird, but we decided to
253 // accept such configurations.
254 continue;
255 }
256
257 // For each subnet, add it to a list of regular subnets.
258 for (auto const& subnet : *subnets) {
259 dest->add(subnet);
260 }
261 }
262 }
263
272 void
273 sanityChecks(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
274
276 cfg->sanityChecksLifetime("preferred-lifetime");
277 cfg->sanityChecksLifetime("valid-lifetime");
278
280 const SharedNetwork6Collection* networks = cfg->getCfgSharedNetworks6()->getAll();
281 if (networks) {
282 sharedNetworksSanityChecks(*networks, global->get("shared-networks"));
283 }
284 }
285
292 void
293 sharedNetworksSanityChecks(const SharedNetwork6Collection& networks,
294 ConstElementPtr json) {
295
297 if (!json) {
298 // No json? That means that the shared-networks was never specified
299 // in the config.
300 return;
301 }
302
303 // Used for names uniqueness checks.
304 std::set<string> names;
305
306 // Let's go through all the networks one by one
307 for (auto const& net : networks) {
308 string txt;
309
310 // Let's check if all subnets have either the same interface
311 // or don't have the interface specified at all.
312 string iface = net->getIface();
313
314 const Subnet6SimpleCollection* subnets = net->getAllSubnets();
315 if (subnets) {
316
317 bool rapid_commit = false;
318
319 // Rapid commit must either be enabled or disabled in all subnets
320 // in the shared network.
321 if (subnets->size()) {
322 // If this is the first subnet, remember the value.
323 rapid_commit = (*subnets->begin())->getRapidCommit();
324 }
325
326 // For each subnet, add it to a list of regular subnets.
327 for (auto const& subnet : *subnets) {
328 // Ok, this is the second or following subnets. The value
329 // must match what was set in the first subnet.
330 if (rapid_commit != subnet->getRapidCommit()) {
331 isc_throw(DhcpConfigError, "All subnets in a shared network "
332 "must have the same rapid-commit value. Subnet "
333 << subnet->toText()
334 << " has specified rapid-commit "
335 << (subnet->getRapidCommit() ? "true" : "false")
336 << ", but earlier subnet in the same shared-network"
337 << " or the shared-network itself used rapid-commit "
338 << (rapid_commit ? "true" : "false"));
339 }
340
341 if (iface.empty()) {
342 iface = subnet->getIface();
343 continue;
344 }
345
346 if (subnet->getIface().empty()) {
347 continue;
348 }
349
350 if (subnet->getIface() != iface) {
351 isc_throw(DhcpConfigError, "Subnet " << subnet->toText()
352 << " has specified interface " << subnet->getIface()
353 << ", but earlier subnet in the same shared-network"
354 << " or the shared-network itself used " << iface);
355 }
356
357 // Let's collect the subnets in case we later find out the
358 // subnet doesn't have a mandatory name.
359 txt += subnet->toText() + " ";
360 }
361 }
362
363 // Next, let's check name of the shared network.
364 if (net->getName().empty()) {
365 isc_throw(DhcpConfigError, "Shared-network with subnets "
366 << txt << " is missing mandatory 'name' parameter");
367 }
368
369 // Is it unique?
370 if (names.find(net->getName()) != names.end()) {
371 isc_throw(DhcpConfigError, "A shared-network with "
372 "name " << net->getName() << " defined twice.");
373 }
374 names.insert(net->getName());
375
376 }
377 }
378};
379
380} // anonymous namespace
381
382namespace isc {
383namespace dhcp {
384
393 // Get new socket configuration.
394 ConstElementPtr sock_cfg =
395 CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
396
397 // Get current socket configuration.
398 ConstElementPtr current_sock_cfg =
399 CfgMgr::instance().getCurrentCfg()->getControlSocketInfo();
400
401 // Determine if the socket configuration has changed. It has if
402 // both old and new configuration is specified but respective
403 // data elements aren't equal.
404 bool sock_changed = (sock_cfg && current_sock_cfg &&
405 !sock_cfg->equals(*current_sock_cfg));
406
407 // If the previous or new socket configuration doesn't exist or
408 // the new configuration differs from the old configuration we
409 // close the existing socket and open a new socket as appropriate.
410 // Note that closing an existing socket means the client will not
411 // receive the configuration result.
412 if (!sock_cfg || !current_sock_cfg || sock_changed) {
413 // Close the existing socket (if any).
415
416 if (sock_cfg) {
417 // This will create a control socket and install the external
418 // socket in IfaceMgr. That socket will be monitored when
419 // Dhcp6Srv::receivePacket() calls IfaceMgr::receive6() and
420 // callback in CommandMgr will be called, if necessary.
422 }
423 }
424}
425
432 // Before starting any subnet operations, let's reset the subnet-id counter,
433 // so newly recreated configuration starts with first subnet-id equal 1.
435
436 // Revert any runtime option definitions configured so far and not committed.
438 // Let's set empty container in case a user hasn't specified any configuration
439 // for option definitions. This is equivalent to committing empty container.
441
442 // Print the list of known backends.
444
445 // Answer will hold the result.
446 ConstElementPtr answer;
447
448 // Global parameter name in case of an error.
449 string parameter_name;
450 ElementPtr mutable_cfg;
451 SrvConfigPtr srv_config;
452 try {
453 // Get the staging configuration.
454 srv_config = CfgMgr::instance().getStagingCfg();
455
456 // This is a way to convert ConstElementPtr to ElementPtr.
457 // We need a config that can be edited, because we will insert
458 // default values and will insert derived values as well.
459 mutable_cfg = boost::const_pointer_cast<Element>(config_set);
460
461 // Relocate dhcp-ddns parameters that have moved to global scope.
462 // Rule is that a global value overrides the dhcp-ddns value, so
463 // we need to do this before we apply global defaults.
464 // Note this is done for backward compatibility.
465 srv_config->moveDdnsParams(mutable_cfg);
466
467 // Move from reservation mode to new reservations flags.
468 // @todo add warning
470
471 // Set all default values if not specified by the user.
473
474 // And now derive (inherit) global parameters to subnets, if not specified.
476
477 // In principle we could have the following code structured as a series
478 // of long if else if clauses. That would give a marginal performance
479 // boost, but would make the code less readable. We had serious issues
480 // with the parser code debugability, so I decided to keep it as a
481 // series of independent ifs.
482
483 // This parser is used in several places.
484 Dhcp6ConfigParser global_parser;
485
486 // Apply global options in the staging config, e.g. ip-reservations-unique
487 global_parser.parseEarly(srv_config, mutable_cfg);
488
489 // Specific check for this global parameter.
490 ConstElementPtr data_directory = mutable_cfg->get("data-directory");
491 if (data_directory) {
492 parameter_name = "data-directory";
493 dirExists(data_directory->stringValue());
494 }
495
496 // We need definitions first
497 ConstElementPtr option_defs = mutable_cfg->get("option-def");
498 if (option_defs) {
499 parameter_name = "option-def";
500 OptionDefListParser parser(AF_INET6);
501 CfgOptionDefPtr cfg_option_def = srv_config->getCfgOptionDef();
502 parser.parse(cfg_option_def, option_defs);
503 }
504
505 ConstElementPtr option_datas = mutable_cfg->get("option-data");
506 if (option_datas) {
507 parameter_name = "option-data";
508 OptionDataListParser parser(AF_INET6);
509 CfgOptionPtr cfg_option = srv_config->getCfgOption();
510 parser.parse(cfg_option, option_datas);
511 }
512
513 ConstElementPtr mac_sources = mutable_cfg->get("mac-sources");
514 if (mac_sources) {
515 parameter_name = "mac-sources";
517 CfgMACSource& mac_source = srv_config->getMACSources();
518 parser.parse(mac_source, mac_sources);
519 }
520
521 ConstElementPtr control_socket = mutable_cfg->get("control-socket");
522 if (control_socket) {
523 parameter_name = "control-socket";
524 ControlSocketParser parser;
525 parser.parse(*srv_config, control_socket);
526 }
527
528 ConstElementPtr multi_threading = mutable_cfg->get("multi-threading");
529 if (multi_threading) {
530 parameter_name = "multi-threading";
532 parser.parse(*srv_config, multi_threading);
533 }
534
535 bool multi_threading_enabled = true;
536 uint32_t thread_count = 0;
537 uint32_t queue_size = 0;
538 CfgMultiThreading::extract(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading(),
539 multi_threading_enabled, thread_count, queue_size);
540
542 ConstElementPtr queue_control = mutable_cfg->get("dhcp-queue-control");
543 if (queue_control) {
544 parameter_name = "dhcp-queue-control";
546 srv_config->setDHCPQueueControl(parser.parse(queue_control, multi_threading_enabled));
547 }
548
550 ConstElementPtr reservations_lookup_first = mutable_cfg->get("reservations-lookup-first");
551 if (reservations_lookup_first) {
552 parameter_name = "reservations-lookup-first";
553 if (multi_threading_enabled) {
555 }
556 srv_config->setReservationsLookupFirst(reservations_lookup_first->boolValue());
557 }
558
559 ConstElementPtr hr_identifiers =
560 mutable_cfg->get("host-reservation-identifiers");
561 if (hr_identifiers) {
562 parameter_name = "host-reservation-identifiers";
564 parser.parse(hr_identifiers);
565 }
566
567 ConstElementPtr server_id = mutable_cfg->get("server-id");
568 if (server_id) {
569 parameter_name = "server-id";
570 DUIDConfigParser parser;
571 const CfgDUIDPtr& cfg = srv_config->getCfgDUID();
572 parser.parse(cfg, server_id);
573 }
574
575 ConstElementPtr sanity_checks = mutable_cfg->get("sanity-checks");
576 if (sanity_checks) {
577 parameter_name = "sanity-checks";
578 SanityChecksParser parser;
579 parser.parse(*srv_config, sanity_checks);
580 }
581
582 ConstElementPtr expiration_cfg =
583 mutable_cfg->get("expired-leases-processing");
584 if (expiration_cfg) {
585 parameter_name = "expired-leases-processing";
587 parser.parse(expiration_cfg, CfgMgr::instance().getStagingCfg()->getCfgExpiration());
588 }
589
590 // The hooks-libraries configuration must be parsed after parsing
591 // multi-threading configuration so that libraries are checked
592 // for multi-threading compatibility.
593 ConstElementPtr hooks_libraries = mutable_cfg->get("hooks-libraries");
594 if (hooks_libraries) {
595 parameter_name = "hooks-libraries";
596 HooksLibrariesParser hooks_parser;
597 HooksConfig& libraries = srv_config->getHooksConfig();
598 hooks_parser.parse(libraries, hooks_libraries);
599 libraries.verifyLibraries(hooks_libraries->getPosition(),
600 multi_threading_enabled);
601 }
602
603 // D2 client configuration.
604 D2ClientConfigPtr d2_client_cfg;
605
606 // Legacy DhcpConfigParser stuff below.
607 ConstElementPtr dhcp_ddns = mutable_cfg->get("dhcp-ddns");
608 if (dhcp_ddns) {
609 parameter_name = "dhcp-ddns";
610 // Apply defaults
613 d2_client_cfg = parser.parse(dhcp_ddns);
614 }
615
616 ConstElementPtr client_classes = mutable_cfg->get("client-classes");
617 if (client_classes) {
618 parameter_name = "client-classes";
620 ClientClassDictionaryPtr dictionary =
621 parser.parse(client_classes, AF_INET6);
622 srv_config->setClientClassDictionary(dictionary);
623 }
624
625 // Please move at the end when migration will be finished.
626 ConstElementPtr lease_database = mutable_cfg->get("lease-database");
627 if (lease_database) {
628 parameter_name = "lease-database";
629 db::DbAccessParser parser;
630 std::string access_string;
631 parser.parse(access_string, lease_database);
632 CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
633 cfg_db_access->setLeaseDbAccessString(access_string);
634 }
635
636 ConstElementPtr hosts_database = mutable_cfg->get("hosts-database");
637 if (hosts_database) {
638 parameter_name = "hosts-database";
639 db::DbAccessParser parser;
640 std::string access_string;
641 parser.parse(access_string, hosts_database);
642 CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
643 cfg_db_access->setHostDbAccessString(access_string);
644 }
645
646 ConstElementPtr hosts_databases = mutable_cfg->get("hosts-databases");
647 if (hosts_databases) {
648 parameter_name = "hosts-databases";
649 CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
650 for (auto const& it : hosts_databases->listValue()) {
651 db::DbAccessParser parser;
652 std::string access_string;
653 parser.parse(access_string, it);
654 cfg_db_access->setHostDbAccessString(access_string);
655 }
656 }
657
658 // Keep relative orders of shared networks and subnets.
659 ConstElementPtr shared_networks = mutable_cfg->get("shared-networks");
660 if (shared_networks) {
661 parameter_name = "shared-networks";
668 CfgSharedNetworks6Ptr cfg = srv_config->getCfgSharedNetworks6();
669 parser.parse(cfg, shared_networks);
670
671 // We also need to put the subnets it contains into normal
672 // subnets list.
673 global_parser.copySubnets6(srv_config->getCfgSubnets6(), cfg);
674 }
675
676 ConstElementPtr subnet6 = mutable_cfg->get("subnet6");
677 if (subnet6) {
678 parameter_name = "subnet6";
679 Subnets6ListConfigParser subnets_parser;
680 // parse() returns number of subnets parsed. We may log it one day.
681 subnets_parser.parse(srv_config, subnet6);
682 }
683
684 ConstElementPtr reservations = mutable_cfg->get("reservations");
685 if (reservations) {
686 parameter_name = "reservations";
687 HostCollection hosts;
689 parser.parse(SUBNET_ID_GLOBAL, reservations, hosts);
690 for (auto const& h : hosts) {
691 srv_config->getCfgHosts()->add(h);
692 }
693 }
694
695 ConstElementPtr config_control = mutable_cfg->get("config-control");
696 if (config_control) {
697 parameter_name = "config-control";
698 ConfigControlParser parser;
699 ConfigControlInfoPtr config_ctl_info = parser.parse(config_control);
700 CfgMgr::instance().getStagingCfg()->setConfigControlInfo(config_ctl_info);
701 }
702
703 ConstElementPtr rsoo_list = mutable_cfg->get("relay-supplied-options");
704 if (rsoo_list) {
705 parameter_name = "relay-supplied-options";
706 RSOOListConfigParser parser;
707 parser.parse(srv_config, rsoo_list);
708 }
709
710 ConstElementPtr compatibility = mutable_cfg->get("compatibility");
711 if (compatibility) {
712 CompatibilityParser parser;
713 parser.parse(compatibility, *CfgMgr::instance().getStagingCfg());
714 }
715
716 // Make parsers grouping.
717 const std::map<std::string, ConstElementPtr>& values_map =
718 mutable_cfg->mapValue();
719
720 for (auto const& config_pair : values_map) {
721 parameter_name = config_pair.first;
722
723 // These are converted to SimpleParser and are handled already above.
724 if ((config_pair.first == "data-directory") ||
725 (config_pair.first == "option-def") ||
726 (config_pair.first == "option-data") ||
727 (config_pair.first == "mac-sources") ||
728 (config_pair.first == "control-socket") ||
729 (config_pair.first == "multi-threading") ||
730 (config_pair.first == "dhcp-queue-control") ||
731 (config_pair.first == "host-reservation-identifiers") ||
732 (config_pair.first == "server-id") ||
733 (config_pair.first == "interfaces-config") ||
734 (config_pair.first == "sanity-checks") ||
735 (config_pair.first == "expired-leases-processing") ||
736 (config_pair.first == "hooks-libraries") ||
737 (config_pair.first == "dhcp-ddns") ||
738 (config_pair.first == "client-classes") ||
739 (config_pair.first == "lease-database") ||
740 (config_pair.first == "hosts-database") ||
741 (config_pair.first == "hosts-databases") ||
742 (config_pair.first == "subnet6") ||
743 (config_pair.first == "shared-networks") ||
744 (config_pair.first == "reservations") ||
745 (config_pair.first == "config-control") ||
746 (config_pair.first == "relay-supplied-options") ||
747 (config_pair.first == "loggers") ||
748 (config_pair.first == "compatibility")) {
749 continue;
750 }
751
752 // As of Kea 1.6.0 we have two ways of inheriting the global parameters.
753 // The old method is used in JSON configuration parsers when the global
754 // parameters are derived into the subnets and shared networks and are
755 // being treated as explicitly specified. The new way used by the config
756 // backend is the dynamic inheritance whereby each subnet and shared
757 // network uses a callback function to return global parameter if it
758 // is not specified at lower level. This callback uses configured globals.
759 // We deliberately include both default and explicitly specified globals
760 // so as the callback can access the appropriate global values regardless
761 // whether they are set to a default or other value.
762 if ( (config_pair.first == "renew-timer") ||
763 (config_pair.first == "rebind-timer") ||
764 (config_pair.first == "preferred-lifetime") ||
765 (config_pair.first == "min-preferred-lifetime") ||
766 (config_pair.first == "max-preferred-lifetime") ||
767 (config_pair.first == "valid-lifetime") ||
768 (config_pair.first == "min-valid-lifetime") ||
769 (config_pair.first == "max-valid-lifetime") ||
770 (config_pair.first == "decline-probation-period") ||
771 (config_pair.first == "dhcp4o6-port") ||
772 (config_pair.first == "server-tag") ||
773 (config_pair.first == "reservation-mode") ||
774 (config_pair.first == "reservations-global") ||
775 (config_pair.first == "reservations-in-subnet") ||
776 (config_pair.first == "reservations-out-of-pool") ||
777 (config_pair.first == "calculate-tee-times") ||
778 (config_pair.first == "t1-percent") ||
779 (config_pair.first == "t2-percent") ||
780 (config_pair.first == "cache-threshold") ||
781 (config_pair.first == "cache-max-age") ||
782 (config_pair.first == "hostname-char-set") ||
783 (config_pair.first == "hostname-char-replacement") ||
784 (config_pair.first == "ddns-send-updates") ||
785 (config_pair.first == "ddns-override-no-update") ||
786 (config_pair.first == "ddns-override-client-update") ||
787 (config_pair.first == "ddns-replace-client-name") ||
788 (config_pair.first == "ddns-generated-prefix") ||
789 (config_pair.first == "ddns-qualifying-suffix") ||
790 (config_pair.first == "ddns-update-on-renew") ||
791 (config_pair.first == "ddns-use-conflict-resolution") ||
792 (config_pair.first == "ddns-conflict-resolution-mode") ||
793 (config_pair.first == "ddns-ttl-percent") ||
794 (config_pair.first == "store-extended-info") ||
795 (config_pair.first == "statistic-default-sample-count") ||
796 (config_pair.first == "statistic-default-sample-age") ||
797 (config_pair.first == "early-global-reservations-lookup") ||
798 (config_pair.first == "ip-reservations-unique") ||
799 (config_pair.first == "reservations-lookup-first") ||
800 (config_pair.first == "parked-packet-limit") ||
801 (config_pair.first == "allocator") ||
802 (config_pair.first == "pd-allocator") ) {
803 CfgMgr::instance().getStagingCfg()->addConfiguredGlobal(config_pair.first,
804 config_pair.second);
805 continue;
806 }
807
808 // Nothing to configure for the user-context.
809 if (config_pair.first == "user-context") {
810 continue;
811 }
812
813 // If we got here, no code handled this parameter, so we bail out.
815 "unsupported global configuration parameter: " << config_pair.first
816 << " (" << config_pair.second->getPosition() << ")");
817 }
818
819 // Reset parameter name.
820 parameter_name = "<post parsing>";
821
822 // Apply global options in the staging config.
823 global_parser.parse(srv_config, mutable_cfg);
824
825 // This method conducts final sanity checks and tweaks. In particular,
826 // it checks that there is no conflict between plain subnets and those
827 // defined as part of shared networks.
828 global_parser.sanityChecks(srv_config, mutable_cfg);
829
830 // Validate D2 client configuration.
831 if (!d2_client_cfg) {
832 d2_client_cfg.reset(new D2ClientConfig());
833 }
834 d2_client_cfg->validateContents();
835 srv_config->setD2ClientConfig(d2_client_cfg);
836 } catch (const isc::Exception& ex) {
838 .arg(parameter_name).arg(ex.what());
840 } catch (...) {
841 // For things like bad_cast in boost::lexical_cast
842 LOG_ERROR(dhcp6_logger, DHCP6_PARSER_EXCEPTION).arg(parameter_name);
843 answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration "
844 "processing error");
845 }
846
847 if (!answer) {
848 answer = isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Configuration seems sane. "
849 "Control-socket, hook-libraries, and D2 configuration "
850 "were sanity checked, but not applied.");
851 }
852
853 return (answer);
854}
855
858 bool check_only, bool extra_checks) {
859 if (!config_set) {
861 "Can't parse NULL config");
862 return (answer);
863 }
864
866 .arg(server.redactConfig(config_set)->str());
867
868 auto answer = processDhcp6Config(config_set);
869
870 int status_code = CONTROL_RESULT_SUCCESS;
871 isc::config::parseAnswer(status_code, answer);
872
873 SrvConfigPtr srv_config;
874
875 if (status_code == CONTROL_RESULT_SUCCESS) {
876 if (check_only) {
877 if (extra_checks) {
878 // Re-open lease and host database with new parameters.
879 try {
880 // Get the staging configuration.
881 srv_config = CfgMgr::instance().getStagingCfg();
882
883 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
884 string params = "universe=6 persist=false";
885 if (cfg_db->getExtendedInfoTablesEnabled()) {
886 params += " extended-info-tables=true";
887 }
888 cfg_db->setAppendedParameters(params);
889 cfg_db->createManagers();
890 } catch (const std::exception& ex) {
892 status_code = CONTROL_RESULT_ERROR;
893 }
894
895 if (status_code == CONTROL_RESULT_SUCCESS) {
896 std::ostringstream err;
897 // Configure DHCP packet queueing
898 try {
900 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
901 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, qc)) {
903 .arg(IfaceMgr::instance().getPacketQueue6()->getInfoStr());
904 }
905
906 } catch (const std::exception& ex) {
907 err << "Error setting packet queue controls after server reconfiguration: "
908 << ex.what();
910 status_code = CONTROL_RESULT_ERROR;
911 }
912 }
913 }
914 } else {
915 // disable multi-threading (it will be applied by new configuration)
916 // this must be done in order to properly handle MT to ST transition
917 // when 'multi-threading' structure is missing from new config and
918 // to properly drop any task items stored in the thread pool which
919 // might reference some handles to loaded hooks, preventing them
920 // from being unloaded.
921 MultiThreadingMgr::instance().apply(false, 0, 0);
922
923 // Close DHCP sockets and remove any existing timers.
925 TimerMgr::instance()->unregisterTimers();
926 server.discardPackets();
927 server.getCBControl()->reset();
928 }
929
930 if (status_code == CONTROL_RESULT_SUCCESS) {
931 string parameter_name;
932 ElementPtr mutable_cfg;
933 try {
934 // Get the staging configuration.
935 srv_config = CfgMgr::instance().getStagingCfg();
936
937 // This is a way to convert ConstElementPtr to ElementPtr.
938 // We need a config that can be edited, because we will insert
939 // default values and will insert derived values as well.
940 mutable_cfg = boost::const_pointer_cast<Element>(config_set);
941
942 ConstElementPtr ifaces_config = mutable_cfg->get("interfaces-config");
943 if (ifaces_config) {
944 parameter_name = "interfaces-config";
945 IfacesConfigParser parser(AF_INET6, check_only);
946 CfgIfacePtr cfg_iface = srv_config->getCfgIface();
947 cfg_iface->reset();
948 parser.parse(cfg_iface, ifaces_config);
949 }
950 } catch (const isc::Exception& ex) {
952 .arg(parameter_name).arg(ex.what());
954 status_code = CONTROL_RESULT_ERROR;
955 } catch (...) {
956 // For things like bad_cast in boost::lexical_cast
957 LOG_ERROR(dhcp6_logger, DHCP6_PARSER_EXCEPTION).arg(parameter_name);
958 answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
959 " processing error");
960 status_code = CONTROL_RESULT_ERROR;
961 }
962 }
963 }
964
965 // So far so good, there was no parsing error so let's commit the
966 // configuration. This will add created subnets and option values into
967 // the server's configuration.
968 // This operation should be exception safe but let's make sure.
969 if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
970 try {
971
972 // Setup the command channel.
974 } catch (const isc::Exception& ex) {
977 status_code = CONTROL_RESULT_ERROR;
978 } catch (...) {
979 // For things like bad_cast in boost::lexical_cast
981 answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
982 " parsing error");
983 status_code = CONTROL_RESULT_ERROR;
984 }
985 }
986
987 if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
988 try {
989 // No need to commit interface names as this is handled by the
990 // CfgMgr::commit() function.
991
992 // Apply the staged D2ClientConfig, used to be done by parser commit
994 cfg = CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
996 } catch (const isc::Exception& ex) {
999 status_code = CONTROL_RESULT_ERROR;
1000 } catch (...) {
1001 // For things like bad_cast in boost::lexical_cast
1003 answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
1004 " parsing error");
1005 status_code = CONTROL_RESULT_ERROR;
1006 }
1007 }
1008
1009 if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
1010 try {
1011 // This occurs last as if it succeeds, there is no easy way to
1012 // revert it. As a result, the failure to commit a subsequent
1013 // change causes problems when trying to roll back.
1015 static_cast<void>(HooksManager::unloadLibraries());
1017 const HooksConfig& libraries =
1018 CfgMgr::instance().getStagingCfg()->getHooksConfig();
1019 bool multi_threading_enabled = true;
1020 uint32_t thread_count = 0;
1021 uint32_t queue_size = 0;
1022 CfgMultiThreading::extract(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading(),
1023 multi_threading_enabled, thread_count, queue_size);
1024 libraries.loadLibraries(multi_threading_enabled);
1025 } catch (const isc::Exception& ex) {
1028 status_code = CONTROL_RESULT_ERROR;
1029 } catch (...) {
1030 // For things like bad_cast in boost::lexical_cast
1032 answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
1033 " parsing error");
1034 status_code = CONTROL_RESULT_ERROR;
1035 }
1036 }
1037
1038 // Moved from the commit block to add the config backend indication.
1039 if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
1040 try {
1041 // If there are config backends, fetch and merge into staging config
1042 server.getCBControl()->databaseConfigFetch(srv_config,
1044 } catch (const isc::Exception& ex) {
1045 std::ostringstream err;
1046 err << "during update from config backend database: " << ex.what();
1049 status_code = CONTROL_RESULT_ERROR;
1050 } catch (...) {
1051 // For things like bad_cast in boost::lexical_cast
1052 std::ostringstream err;
1053 err << "during update from config backend database: "
1054 << "undefined configuration parsing error";
1057 status_code = CONTROL_RESULT_ERROR;
1058 }
1059 }
1060
1061 // Rollback changes as the configuration parsing failed.
1062 if (check_only || status_code != CONTROL_RESULT_SUCCESS) {
1063 // Revert to original configuration of runtime option definitions
1064 // in the libdhcp++.
1066
1067 if (status_code == CONTROL_RESULT_SUCCESS && extra_checks) {
1068 auto notify_libraries = ControlledDhcpv6Srv::finishConfigHookLibraries(config_set);
1069 if (notify_libraries) {
1070 return (notify_libraries);
1071 }
1072
1074 try {
1075 // Handle events registered by hooks using external IOService objects.
1077 } catch (const std::exception& ex) {
1078 std::ostringstream err;
1079 err << "Error initializing hooks: "
1080 << ex.what();
1082 }
1083 }
1084
1085 return (answer);
1086 }
1087
1089 .arg(CfgMgr::instance().getStagingCfg()->
1090 getConfigSummary(SrvConfig::CFGSEL_ALL6));
1091
1092 // Also calculate SHA256 hash of the config that was just set and
1093 // append it to the response.
1094 ConstElementPtr config = CfgMgr::instance().getStagingCfg()->toElement();
1095 string hash = BaseCommandMgr::getHash(config);
1096 ElementPtr hash_map = Element::createMap();
1097 hash_map->set("hash", Element::create(hash));
1098
1099 // Everything was fine. Configuration is successful.
1100 answer = isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Configuration successful.", hash_map);
1101 return (answer);
1102}
1103
1104} // namespace dhcp
1105} // namespace isc
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.
static std::string getHash(const isc::data::ConstElementPtr &config)
returns a hash of a given Element structure
void closeCommandSocket()
Shuts down any open control sockets.
Definition: command_mgr.cc:624
static CommandMgr & instance()
CommandMgr is a singleton class.
Definition: command_mgr.cc:646
void openCommandSocket(const isc::data::ConstElementPtr &socket_info)
Opens control socket with parameters specified in socket_info.
Definition: command_mgr.cc:620
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 std::string getString(isc::data::ConstElementPtr scope, const std::string &name)
Returns a string parameter from a scope.
uint32_t getUint32(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint32_t.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
uint16_t getUint16(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint16_t.
Parse Database Parameters.
void parse(std::string &access_string, isc::data::ConstElementPtr database_config)
Parse configuration value.
static void moveReservationMode(isc::data::ElementPtr config)
Moves deprecated reservation-mode parameter to new reservations flags.
Wrapper class that holds MAC/hardware address sources.
void setD2ClientConfig(D2ClientConfigPtr &new_config)
Updates the DHCP-DDNS client configuration to the given value.
Definition: cfgmgr.cc:41
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
void setDataDir(const std::string &datadir, bool unspecified=true)
Sets new data directory.
Definition: cfgmgr.cc:36
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition: cfgmgr.cc:167
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
static void extract(data::ConstElementPtr value, bool &enabled, uint32_t &thread_count, uint32_t &queue_size)
Extract multi-threading parameters from a given configuration.
Parser for a list of client class definitions.
ClientClassDictionaryPtr parse(isc::data::ConstElementPtr class_def_list, uint16_t family, bool check_dependencies=true)
Parse configuration entries.
void parse(isc::data::ConstElementPtr cfg, isc::dhcp::SrvConfig &srv_cfg)
Parse compatibility flags.
Parser for the control-socket structure.
Definition: dhcp_parsers.h:211
void parse(SrvConfig &srv_cfg, isc::data::ConstElementPtr value)
"Parses" control-socket structure
Definition: dhcp_parsers.cc:77
static isc::data::ConstElementPtr finishConfigHookLibraries(isc::data::ConstElementPtr config)
Configuration checker for hook libraries.
Parser for D2ClientConfig.
D2ClientConfigPtr parse(isc::data::ConstElementPtr d2_client_cfg)
Parses a given dhcp-ddns element into D2ClientConfig.
static size_t setAllDefaults(isc::data::ConstElementPtr d2_config)
Sets all defaults for D2 client configuration.
Acts as a storage vault for D2 client configuration.
Definition: d2_client_cfg.h:57
Parser for the configuration of DHCP packet queue controls.
data::ElementPtr parse(const isc::data::ConstElementPtr &control_elem, bool multi_threading_enabled)
Parses content of the "dhcp-queue-control".
Parser for server DUID configuration.
void parse(const CfgDUIDPtr &cfg, isc::data::ConstElementPtr duid_configuration)
Parses DUID configuration.
To be removed. Please use ConfigError instead.
DHCPv6 server service.
Definition: dhcp6_srv.h:66
CBControlDHCPv6Ptr getCBControl() const
Returns an object which controls access to the configuration backends.
Definition: dhcp6_srv.h:124
void discardPackets()
Discards parked packets Clears the packet parking lots of all packets.
Definition: dhcp6_srv.cc:4843
Parser for the configuration parameters pertaining to the processing of expired leases.
void parse(isc::data::ConstElementPtr expiration_config, isc::dhcp::CfgExpirationPtr expiration)
Parses parameters in the JSON map, pertaining to the processing of the expired leases.
static void printRegistered()
Prints out all registered backends.
Parser for a list of host identifiers for DHCPv6.
void parse(isc::data::ConstElementPtr ids_list)
Parses a list of host identifiers.
Parser for a list of host reservations for a subnet.
void parse(const SubnetID &subnet_id, isc::data::ConstElementPtr hr_list, HostCollection &hosts_list)
Parses a list of host reservation entries for a subnet.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:54
void closeSockets()
Closes all open sockets.
Definition: iface_mgr.cc:286
Parser for the configuration of interfaces.
void parse(const CfgIfacePtr &config, const isc::data::ConstElementPtr &values)
Parses content of the "interfaces-config".
static void setRuntimeOptionDefs(const OptionDefSpaceContainer &defs)
Copies option definitions created at runtime.
Definition: libdhcp++.cc:218
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition: libdhcp++.cc:126
static void revertRuntimeOptionDefs()
Reverts uncommitted changes to runtime option definitions.
Definition: libdhcp++.cc:237
parser for MAC/hardware acquisition sources
Definition: dhcp_parsers.h:195
void parse(CfgMACSource &mac_sources, isc::data::ConstElementPtr value)
parses parameters value
Definition: dhcp_parsers.cc:47
Simple parser for multi-threading structure.
void parse(SrvConfig &srv_cfg, const isc::data::ConstElementPtr &value)
parses JSON structure.
Parser for option data values within a subnet.
void parse(const CfgOptionPtr &cfg, isc::data::ConstElementPtr option_data_list, bool encapsulate=true)
Parses a list of options, instantiates them and stores in cfg.
Parser for a list of option definitions.
Definition: dhcp_parsers.h:254
void parse(CfgOptionDefPtr cfg, isc::data::ConstElementPtr def_list)
Parses a list of option definitions, create them and store in cfg.
Class of option definition space container.
Simple parser for sanity-checks structure.
void parse(SrvConfig &srv_cfg, const isc::data::ConstElementPtr &value)
parses JSON structure
Parser for a list of shared networks.
void parse(CfgSharedNetworksTypePtr &cfg, const data::ConstElementPtr &shared_networks_list_data)
Parses a list of shared networks.
static size_t deriveParameters(isc::data::ElementPtr global)
Derives (inherits) all parameters from global to more specific scopes.
static size_t setAllDefaults(isc::data::ElementPtr global)
Sets all defaults for DHCPv6 configuration.
static const uint32_t CFGSEL_ALL6
IPv6 related config.
Definition: srv_config.h:210
static void resetSubnetID()
Resets subnet-id counter to its initial value (1).
Definition: subnet.h:219
this class parses a list of DHCP6 subnets
Definition: dhcp_parsers.h:953
size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list, bool encapsulate_options=true)
parses contents of the list
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:446
Wrapper class that holds hooks libraries configuration.
Definition: hooks_config.h:36
void verifyLibraries(const isc::data::Element::Position &position, bool multi_threading_enabled) const
Verifies that libraries stored in libraries_ are valid.
Definition: hooks_config.cc:20
void loadLibraries(bool multi_threading_enabled) const
Commits hooks libraries configuration.
Definition: hooks_config.cc:57
Parser for hooks library list.
Definition: hooks_parser.h:21
void parse(HooksConfig &libraries, isc::data::ConstElementPtr value)
Parses parameters value.
Definition: hooks_parser.cc:27
static bool unloadLibraries()
Unload libraries.
static void prepareUnloadLibraries()
Prepare the unloading of libraries.
Implements parser for config control information, "config-control".
ConfigControlInfoPtr parse(const data::ConstElementPtr &config_control)
Parses a configuration control Element.
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition: daemon.cc:256
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
void apply(bool enabled, uint32_t thread_count, uint32_t queue_size)
Apply the multi-threading related settings.
Parsers for client class definitions.
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Logging initialization functions.
#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_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
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
void configureCommandChannel()
Initialize the command channel based on the staging configuration.
boost::shared_ptr< CfgDUID > CfgDUIDPtr
Pointer to the Non-const object.
Definition: cfg_duid.h:161
const isc::log::MessageID DHCP6_PARSER_FAIL
const isc::log::MessageID DHCP6_PARSER_EXCEPTION
boost::shared_ptr< D2ClientConfig > D2ClientConfigPtr
Defines a pointer for D2ClientConfig instances.
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition: cfg_option.h:803
boost::multi_index_container< SharedNetwork6Ptr, boost::multi_index::indexed_by< boost::multi_index::random_access< boost::multi_index::tag< SharedNetworkRandomAccessIndexTag > >, boost::multi_index::hashed_non_unique< boost::multi_index::tag< SharedNetworkIdIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, uint64_t, &data::BaseStampedElement::getId > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SharedNetworkNameIndexTag >, boost::multi_index::const_mem_fun< SharedNetwork6, std::string, &SharedNetwork6::getName > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SharedNetworkModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > > > > SharedNetwork6Collection
Multi index container holding shared networks.
isc::data::ConstElementPtr configureDhcp6Server(Dhcpv6Srv &server, isc::data::ConstElementPtr config_set, bool check_only, bool extra_checks)
Configure DHCPv6 server (Dhcpv6Srv) with a set of configuration values.
boost::shared_ptr< CfgOptionDef > CfgOptionDefPtr
Non-const pointer.
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
isc::data::ConstElementPtr processDhcp6Config(isc::data::ConstElementPtr config_set)
Process a DHCPv6 confguration and return an answer stating if the configuration is valid,...
const int DBG_DHCP6_COMMAND
Debug level used to log receiving commands.
Definition: dhcp6_log.h:28
const isc::log::MessageID DHCP6_CONFIG_COMPLETE
boost::shared_ptr< CfgIface > CfgIfacePtr
A pointer to the CfgIface .
Definition: cfg_iface.h:501
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
Definition: srv_config.h:1267
boost::shared_ptr< CfgSubnets6 > CfgSubnets6Ptr
Non-const pointer.
Definition: cfg_subnets6.h:348
std::vector< HostPtr > HostCollection
Collection of the Host objects.
Definition: host.h:816
const isc::log::MessageID DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
boost::shared_ptr< ClientClassDictionary > ClientClassDictionaryPtr
Defines a pointer to a ClientClassDictionary.
boost::shared_ptr< CfgSharedNetworks6 > CfgSharedNetworks6Ptr
Pointer to the configuration of IPv6 shared networks.
boost::multi_index_container< Subnet6Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID, &Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string, &Subnet::toText > > > > Subnet6SimpleCollection
A simple collection of Subnet6 objects.
Definition: subnet.h:927
const isc::log::MessageID DHCP6_PARSER_COMMIT_EXCEPTION
const isc::log::MessageID DHCP6_CONFIG_START
const isc::log::MessageID DHCP6_PARSER_COMMIT_FAIL
isc::log::Logger dhcp6_logger(DHCP6_APP_LOGGER_NAME)
Base logger for DHCPv6 server.
Definition: dhcp6_log.h:88
const isc::log::MessageID DHCP6_CONFIG_PACKET_QUEUE
boost::shared_ptr< ConfigControlInfo > ConfigControlInfoPtr
Defines a pointer to a ConfigControlInfo.
Defines the logger used by the top-level component of kea-lfc.
#define DHCP6_OPTION_SPACE