--- /dev/null
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <yang/adaptor_config.h>
+
+using namespace std;
+using namespace isc::data;
+using namespace isc::dhcp;
+
+namespace isc {
+namespace yang {
+
+AdaptorConfig::AdaptorConfig() {
+}
+
+AdaptorConfig::~AdaptorConfig() {
+}
+
+bool
+AdaptorConfig::subnetsCollectID(ConstElementPtr subnets, SubnetIDSet& set) {
+ bool have_ids = true;
+ if (subnets && (subnets->size() > 0)) {
+ for (ConstElementPtr subnet : subnets->listValue()) {
+ if (!collectID(subnet, set)) {
+ have_ids = false;
+ }
+ }
+ }
+ return (have_ids);
+}
+
+bool
+AdaptorConfig::shareNetworksCollectID(ConstElementPtr networks,
+ SubnetIDSet& set, const string& subsel) {
+ bool have_ids = true;
+ if (networks && (networks->size() > 0)) {
+ for (size_t i = 0; i < networks->size(); ++i) {
+ ElementPtr network = networks->getNonConst(i);
+ ConstElementPtr subnets = network->get(subsel);
+ if (subnets) {
+ if (subnets->size() > 0) {
+ if (!subnetsCollectID(subnets, set)) {
+ have_ids = false;
+ }
+ } else {
+ network->remove(subsel);
+ }
+ }
+ }
+ }
+ return (have_ids);
+}
+
+void
+AdaptorConfig::subnetsAssignID(ConstElementPtr subnets, SubnetIDSet& set,
+ SubnetID& next) {
+ if (subnets && (subnets->size() > 0)) {
+ for (size_t i = 0; i < subnets->size(); ++i) {
+ ElementPtr subnet = subnets->getNonConst(i);
+ assignID(subnet, set, next);
+ }
+ }
+}
+
+void
+AdaptorConfig::shareNetworksAssignID(ConstElementPtr networks,
+ SubnetIDSet& set, SubnetID& next,
+ const string& subsel) {
+ if (networks && (networks->size() > 0)) {
+ for (ConstElementPtr network : networks->listValue()) {
+ ConstElementPtr subnets = network->get(subsel);
+ if (subnets && (subnets->size() > 0)) {
+ for (size_t i = 0; i < subnets->size(); ++i) {
+ ElementPtr subnet = subnets->getNonConst(i);
+ assignID(subnet, set, next);
+ }
+ }
+ }
+ }
+}
+
+void
+AdaptorConfig::canonizePools(ConstElementPtr pools) {
+ if (pools && (pools->size() > 0)) {
+ for (size_t i = 0; i < pools->size(); ++i) {
+ ElementPtr pool = pools->getNonConst(i);
+ AdaptorPool::canonizePool(pool);
+ }
+ }
+}
+
+void
+AdaptorConfig::poolSubnets(ConstElementPtr subnets) {
+ if (subnets && (subnets->size() > 0)) {
+ for (ConstElementPtr subnet : subnets->listValue()) {
+ canonizePools(subnet->get("pools"));
+ }
+ }
+}
+
+void
+AdaptorConfig::poolShareNetworks(ConstElementPtr networks,
+ const string& subsel) {
+ if (networks && (networks->size() > 0)) {
+ for (ConstElementPtr network : networks->listValue()) {
+ poolSubnets(network->get(subsel));
+ }
+ }
+}
+
+void
+AdaptorConfig::optionDefList(ConstElementPtr defs,
+ const string& space,
+ OptionCodes& codes) {
+ if (defs && (defs->size() > 0)) {
+ for (size_t i = 0; i < defs->size(); ++i) {
+ ElementPtr def = defs->getNonConst(i);
+ checkCode(def);
+ checkType(def);
+ setSpace(def, space);
+ collect(def, codes);
+ }
+ }
+}
+
+void
+AdaptorConfig::optionDataList(ConstElementPtr options,const string& space,
+ const OptionCodes& codes) {
+ if (options && (options->size() > 0)) {
+ for (size_t i = 0; i < options->size(); ++i) {
+ ElementPtr option = options->getNonConst(i);
+ setSpace(option, space);
+ setCode(option, codes);
+ }
+ }
+}
+
+void
+AdaptorConfig::optionClasses(ConstElementPtr classes, const string& space,
+ OptionCodes& codes) {
+ if (classes && (classes->size() > 0)) {
+ for (size_t i = 0; i < classes->size(); ++i) {
+ ElementPtr cclass = classes->getNonConst(i);
+ if (space == "dhcp4") {
+ ConstElementPtr options = cclass->get("option-def");
+ if (options) {
+ if (options->size() > 0) {
+ optionDefList(options, space, codes);
+ } else {
+ cclass->remove("option-def");
+ }
+ }
+ }
+ ConstElementPtr options = cclass->get("option-data");
+ if (options) {
+ if (options->size() > 0) {
+ optionDataList(options, space, codes);
+ } else {
+ cclass->remove("option-data");
+ }
+ }
+ }
+ }
+}
+
+void
+AdaptorConfig::optionPools(ConstElementPtr pools, const string& space,
+ const OptionCodes& codes) {
+ if (pools && (pools->size() > 0)) {
+ for (size_t i = 0; i < pools->size(); ++i) {
+ ElementPtr pool = pools->getNonConst(i);
+ ConstElementPtr options = pool->get("option-data");
+ if (options) {
+ if (options->size() > 0) {
+ optionDataList(options, space, codes);
+ } else {
+ pool->remove("option-data");
+ }
+ }
+ }
+ }
+}
+
+void
+AdaptorConfig::optionHosts(ConstElementPtr hosts, const string& space,
+ const OptionCodes& codes) {
+ if (hosts && (hosts->size() > 0)) {
+ for (size_t i = 0; i < hosts->size(); ++i) {
+ ElementPtr host = hosts->getNonConst(i);
+ ConstElementPtr options = host->get("option-data");
+ if (options) {
+ if (options->size() > 0) {
+ optionDataList(options, space, codes);
+ } else {
+ host->remove("option-data");
+ }
+ }
+ }
+ }
+}
+
+void
+AdaptorConfig::optionSubnets(ConstElementPtr subnets, const string& space,
+ const OptionCodes& codes) {
+ if (subnets && (subnets->size() > 0)) {
+ for (size_t i = 0; i < subnets->size(); ++i) {
+ ElementPtr subnet = subnets->getNonConst(i);
+ ConstElementPtr options = subnet->get("option-data");
+ if (options) {
+ if (options->size() > 0) {
+ optionDataList(options, space, codes);
+ } else {
+ subnet->remove("option-data");
+ }
+ }
+ ConstElementPtr pools = subnet->get("pools");
+ if (pools) {
+ if (pools->size() > 0) {
+ optionPools(pools, space, codes);
+ } else {
+ subnet->remove("pools");
+ }
+ }
+ if (space == "dhcp6") {
+ ConstElementPtr pools = subnet->get("pd-pools");
+ if (pools) {
+ if (pools->size() > 0) {
+ optionPools(pools, space, codes);
+ } else {
+ subnet->remove("pd-pools");
+ }
+ }
+ }
+ ConstElementPtr hosts = subnet->get("reservations");
+ if (hosts) {
+ if (hosts->size() > 0) {
+ optionHosts(hosts, space, codes);
+ } else {
+ subnet->remove("reservations");
+ }
+ }
+ }
+ }
+}
+
+void
+AdaptorConfig::optionSharedNetworks(ConstElementPtr networks,
+ const string& space,
+ const OptionCodes& codes) {
+ if (networks && (networks->size() > 0)) {
+ for (size_t i = 0; i < networks->size(); ++i) {
+ ElementPtr network = networks->getNonConst(i);
+ ConstElementPtr options = network->get("option-data");
+ if (options) {
+ if (options->size() > 0) {
+ optionDataList(options, space, codes);
+ } else {
+ network->remove("option-data");
+ }
+ }
+ string subnet = "subnet";
+ if (space == "dhcp4") {
+ subnet += "4";
+ } else {
+ subnet += "6";
+ }
+ ConstElementPtr subnets = network->get(subnet);
+ if (subnets) {
+ if (subnets->size() > 0) {
+ optionSubnets(subnets, space, codes);
+ } else {
+ network->remove(subnet);
+ }
+ }
+ }
+ }
+}
+
+void
+AdaptorConfig::hostList(ConstElementPtr hosts) {
+ if (hosts && (hosts->size() > 0)) {
+ for (size_t i = 0; i < hosts->size(); ++i) {
+ ElementPtr host = hosts->getNonConst(i);
+ quoteIdentifier(host);
+ }
+ }
+}
+
+void
+AdaptorConfig::hostSubnets(ConstElementPtr subnets) {
+ if (subnets && (subnets->size() > 0)) {
+ for (ConstElementPtr subnet : subnets->listValue()) {
+ hostList(subnet->get("reservations"));
+ }
+ }
+}
+
+void
+AdaptorConfig::hostSharedNetworks(ConstElementPtr networks,
+ const string& space) {
+ if (networks && (networks->size() > 0)) {
+ for (ConstElementPtr network : networks->listValue()) {
+ if (space == "dhcp4") {
+ hostSubnets(network->get("subnet4"));
+ } else {
+ hostSubnets(network->get("subnet6"));
+ }
+ }
+ }
+}
+
+void
+AdaptorConfig::relaySubnets(ConstElementPtr subnets) {
+ if (subnets && (subnets->size() > 0)) {
+ for (size_t i = 0; i < subnets->size(); ++i) {
+ ElementPtr subnet = subnets->getNonConst(i);
+ updateRelay(subnet);
+ }
+ }
+}
+
+void
+AdaptorConfig::relaySharedNetworks(ConstElementPtr networks,
+ const string& subsel) {
+ if (networks && (networks->size() > 0)) {
+ for (size_t i = 0; i < networks->size(); ++i) {
+ ElementPtr network = networks->getNonConst(i);
+ updateRelay(network);
+ relaySubnets(network->get(subsel));
+ }
+ }
+}
+
+void
+AdaptorConfig::updateDatabase(ConstElementPtr dhcp) {
+ ConstElementPtr database = dhcp->get("hosts-database");
+ if (!database) {
+ return;
+ }
+ ElementPtr mutable_dhcp = boost::const_pointer_cast<Element>(dhcp);
+ mutable_dhcp->remove("hosts-database");
+ ElementPtr list = Element::createList();
+ list->add(boost::const_pointer_cast<Element>(database));
+ mutable_dhcp->set("hosts-databases", list);
+}
+
+void
+AdaptorConfig::preProcess(ConstElementPtr dhcp, const string& subsel,
+ const string& space) {
+ ElementPtr mutable_dhcp = boost::const_pointer_cast<Element>(dhcp);
+ bool have_ids = true;
+ SubnetIDSet set;
+ ConstElementPtr subnets = dhcp->get(subsel);
+ if (subnets) {
+ if (subnets->size() > 0) {
+ if (!subnetsCollectID(subnets, set)) {
+ have_ids = false;
+ }
+ } else {
+ mutable_dhcp->remove(subsel);
+ }
+ }
+ ConstElementPtr networks = dhcp->get("shared-networks");
+ if (networks) {
+ if (networks->size() > 0) {
+ if (!shareNetworksCollectID(networks, set, subsel)) {
+ have_ids = false;
+ }
+ } else {
+ mutable_dhcp->remove("shared-networks");
+ }
+ }
+
+ if (!have_ids) {
+ SubnetID next(1);
+ subnetsAssignID(subnets, set, next);
+ shareNetworksAssignID(networks, set, next, subsel);
+ }
+
+ OptionCodes codes;
+ initCodes(codes, space);;
+ ConstElementPtr defs = dhcp->get("option-def");
+ if (defs) {
+ if (defs->size() > 0) {
+ optionDefList(defs, space, codes);
+ } else {
+ mutable_dhcp->remove("option-def");
+ }
+ }
+ ConstElementPtr options = dhcp->get("option-data");
+ if (options) {
+ if (options->size() > 0) {
+ optionDataList(options, space, codes);
+ } else {
+ mutable_dhcp->remove("option-data");
+ }
+ }
+ ConstElementPtr classes = dhcp->get("client-classes");
+ if (classes) {
+ if (classes->size() > 0) {
+ optionClasses(classes, space, codes);
+ } else {
+ mutable_dhcp->remove("client-classes");
+ }
+ }
+ ConstElementPtr hosts = dhcp->get("reservations");
+ if (hosts) {
+ if (hosts->size() > 0) {
+ optionHosts(hosts, space, codes);
+ } else {
+ mutable_dhcp->remove("reservations");
+ }
+ }
+ optionSubnets(subnets, space, codes);
+ optionSharedNetworks(networks, space, codes);
+
+ poolSubnets(subnets);
+ poolShareNetworks(networks, subsel);
+
+ hostSubnets(subnets);
+ hostSharedNetworks(networks, space);
+
+ relaySubnets(subnets);
+ relaySharedNetworks(networks, subsel);
+
+ updateDatabase(dhcp);
+}
+
+void
+AdaptorConfig::preProcess4(ConstElementPtr config) {
+ ConstElementPtr dhcp = config->get("Dhcp4");
+ preProcess(config->get("Dhcp4"), "subnet4", "dhcp4");
+}
+
+void
+AdaptorConfig::preProcess6(ConstElementPtr config) {
+ ConstElementPtr dhcp = config->get("Dhcp6");
+ preProcess(config->get("Dhcp6"), "subnet6", "dhcp6");
+}
+
+}; // end of namespace isc::yang
+}; // end of namespace isc
--- /dev/null
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef ISC_ADAPTOR_CONFIG_H
+#define ISC_ADAPTOR_CONFIG_H 1
+
+#include <yang/adaptor_host.h>
+#include <yang/adaptor_option.h>
+#include <yang/adaptor_pool.h>
+#include <yang/adaptor_subnet.h>
+#include <list>
+
+namespace isc {
+namespace yang {
+
+/// @brief JSON adaptor for configurations.
+class AdaptorConfig : public AdaptorHost, public AdaptorOption,
+ public AdaptorSubnet {
+public:
+
+ /// @brief Constructor.
+ AdaptorConfig();
+
+ /// @brief Destructor.
+ virtual ~AdaptorConfig();
+
+ /// @brief Pre process a DHCPv4 configuration.
+ ///
+ /// Assign subnet IDs, check and set default in options.
+ ///
+ /// @param config The configuration.
+ /// @throw MissingKey when a required key is missing.
+ static void preProcess4(isc::data::ConstElementPtr config);
+
+ /// @brief Pre process a DHCPv6 configuration.
+ ///
+ /// Assign subnet IDs, check and set default in options.
+ ///
+ /// @param config The configuration.
+ /// @throw MissingKey when a required key is missing.
+ static void preProcess6(isc::data::ConstElementPtr config);
+
+protected:
+ /// @brief collectID for a subnet list.
+ ///
+ /// @param subnets The subnet list.
+ /// @param set The reference to the set of assigned IDs.
+ /// @return True if all subnets have an ID, false otherwise.
+ static bool subnetsCollectID(isc::data::ConstElementPtr subnets,
+ SubnetIDSet& set);
+
+ /// @brief collectID for a shared network list.
+ ///
+ /// @param networks The shared network list.
+ /// @param set The reference to the set of assigned IDs.
+ /// @param subsel The subnet list name.
+ /// @return True if all subnets have an ID, false otherwise.
+ static bool shareNetworksCollectID(isc::data::ConstElementPtr networks,
+ SubnetIDSet& set,
+ const std::string& subsel);
+
+ /// @brief assignID for a subnet list.
+ ///
+ /// @param subnets The subnet list.
+ /// @param set The reference to the set of assigned IDs.
+ /// @param next The next ID.
+ /// @return True if all subnets have an ID, false otherwise.
+ static void subnetsAssignID(isc::data::ConstElementPtr subnets,
+ SubnetIDSet& set, isc::dhcp::SubnetID& next);
+
+ /// @brief assignID for a shared network list.
+ ///
+ /// @param networks The shared network list.
+ /// @param set The reference to the set of assigned IDs.
+ /// @param next The next ID.
+ /// @param subsel The subnet list name.
+ /// @return True if all subnets have an ID, false otherwise.
+ static void shareNetworksAssignID(isc::data::ConstElementPtr networks,
+ SubnetIDSet& set,
+ isc::dhcp::SubnetID& next,
+ const std::string& subsel);
+
+ /// @brief canonizePool for a pool list.
+ ///
+ /// @param pools The pool list.
+ static void canonizePools(isc::data::ConstElementPtr pools);
+
+ /// @brief canonizePool for a subnet list.
+ ///
+ /// @param subnets The subnet list.
+ static void poolSubnets(isc::data::ConstElementPtr subnets);
+
+ /// @brief canonizePool for a shared network list.
+ ///
+ /// @param networks The shared network list.
+ /// @param subsel The subnet list name.
+ static void poolShareNetworks(isc::data::ConstElementPtr networks,
+ const std::string& subsel);
+
+ /// @brief Process an option definition list.
+ ///
+ /// @param defs The option definition list.
+ /// @param space The default space name.
+ /// @param codes Option definitions.
+ static void optionDefList(isc::data::ConstElementPtr defs,
+ const std::string& space,
+ OptionCodes& codes);
+
+ /// @brief Process an option data list.
+ ///
+ /// @param options The option data list.
+ /// @param space The default space name.
+ /// @param codes Option definitions.
+ static void optionDataList(isc::data::ConstElementPtr options,
+ const std::string& space,
+ const OptionCodes& codes);
+
+ /// @brief Process options in a client class list.
+ ///
+ /// @param classes The client class list.
+ /// @param space The default space name.
+ /// @param codes Option definitions.
+ static void optionClasses(isc::data::ConstElementPtr classes,
+ const std::string& space,
+ OptionCodes& codes);
+
+ /// @brief Process options in a pool list.
+ ///
+ /// @param pools The pool list.
+ /// @param space The default space name.
+ /// @param codes Option definitions.
+ static void optionPools(isc::data::ConstElementPtr pools,
+ const std::string& space,
+ const OptionCodes& codes);
+
+ /// @brief Process options in a host reservation list.
+ ///
+ /// @param hosts The host reservation list.
+ /// @param space The default space name.
+ /// @param codes Option definitions.
+ static void optionHosts(isc::data::ConstElementPtr hosts,
+ const std::string& space,
+ const OptionCodes& codes);
+
+ /// @brief Process options in a subnet list.
+ ///
+ /// @param subnets The subnet list.
+ /// @param space The default space name.
+ /// @param codes Option definitions.
+ static void optionSubnets(isc::data::ConstElementPtr subnets,
+ const std::string& space,
+ const OptionCodes& codes);
+
+ /// @brief Process options in a shared network list.
+ ///
+ /// @param networks The shared network list.
+ /// @param space The default space name.
+ /// @param codes Option definitions.
+ static void optionSharedNetworks(isc::data::ConstElementPtr networks,
+ const std::string& space,
+ const OptionCodes& codes);
+
+ /// @brief Process host reservation list.
+ ///
+ /// @param hosts The host reservation list.
+ static void hostList(isc::data::ConstElementPtr hosts);
+
+ /// @brief Process host reservations in a subnet list.
+ ///
+ /// @param subnets The subnet list.
+ static void hostSubnets(isc::data::ConstElementPtr subnets);
+
+ /// @brief Process host reservations in a shared network list.
+ ///
+ /// @param networks The shared network list.
+ /// @param space The default space name.
+ static void hostSharedNetworks(isc::data::ConstElementPtr networks,
+ const std::string& space);
+
+ /// @brief updateRelay in a subnet list.
+ ///
+ /// @param subnets The subnet list.
+ static void relaySubnets(isc::data::ConstElementPtr subnets);
+
+ /// @brief updateRelay in a shared network list.
+ ///
+ /// @param networks The shared network list.
+ /// @param subsel The subnet list name.
+ static void relaySharedNetworks(isc::data::ConstElementPtr networks,
+ const std::string& subsel);
+
+ /// @brief Update (hosts) database.
+ ///
+ /// Force the use of hosts-databases vs. hosts-database.
+ ///
+ /// @param dhcp The DHCP server.
+ static void updateDatabase(isc::data::ConstElementPtr dhcp);
+
+ /// @brief Pre process a configuration.
+ ///
+ /// Assign subnet IDs, check and set default in options.
+ ///
+ /// @param dhcp The server configuration.
+ /// @param subsel The subnet list name.
+ /// @param space The default option space name.
+ /// @throw MissingKey when a required key is missing.
+ static void preProcess(isc::data::ConstElementPtr dhcp,
+ const std::string& subsel,
+ const std::string& space);
+};
+
+}; // end of namespace isc::yang
+}; // end of namespace isc
+
+#endif // ISC_ADAPTOR_CONFIG_H