summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcpsrv/cfg_option_def.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 11:36:04 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 11:36:04 +0000
commit040eee1aa49b49df4698d83a05af57c220127fd1 (patch)
treef635435954e6ccde5eee9893889e24f30ca68346 /src/lib/dhcpsrv/cfg_option_def.cc
parentInitial commit. (diff)
downloadisc-kea-upstream.tar.xz
isc-kea-upstream.zip
Adding upstream version 2.2.0.upstream/2.2.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/dhcpsrv/cfg_option_def.cc')
-rw-r--r--src/lib/dhcpsrv/cfg_option_def.cc261
1 files changed, 261 insertions, 0 deletions
diff --git a/src/lib/dhcpsrv/cfg_option_def.cc b/src/lib/dhcpsrv/cfg_option_def.cc
new file mode 100644
index 0000000..02de922
--- /dev/null
+++ b/src/lib/dhcpsrv/cfg_option_def.cc
@@ -0,0 +1,261 @@
+// Copyright (C) 2014-2021 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 <config.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option_data_types.h>
+#include <dhcp/option_definition.h>
+#include <dhcp/option_space.h>
+#include <dhcpsrv/cfg_option_def.h>
+#include <sstream>
+
+using namespace isc::data;
+
+namespace isc {
+namespace dhcp {
+
+void
+CfgOptionDef::copyTo(CfgOptionDef& new_config) const {
+ // Remove any existing option definitions from the destination.
+ new_config.option_definitions_.clearItems();
+ const std::list<std::string>& names =
+ option_definitions_.getOptionSpaceNames();
+ for (std::list<std::string>::const_iterator name = names.begin();
+ name != names.end(); ++name) {
+ OptionDefContainerPtr defs = getAll(*name);
+ for (OptionDefContainer::const_iterator def = defs->begin();
+ def != defs->end(); ++def) {
+ OptionDefinitionPtr new_def =
+ OptionDefinitionPtr(new OptionDefinition(**def));
+ new_config.add(new_def);
+ }
+ }
+}
+
+bool
+CfgOptionDef::equals(const CfgOptionDef& other) const {
+ // Get our option space names.
+ const std::list<std::string>& names = option_definitions_.getOptionSpaceNames();
+ // Get option space names held by the other object.
+ const std::list<std::string>&
+ other_names = other.option_definitions_.getOptionSpaceNames();
+ // Compare that sizes are the same. If they hold different number of
+ // option space names the objects are not equal.
+ if (names.size() != other_names.size()) {
+ return (false);
+ }
+ // Iterate over all option space names and get the definitions for each
+ // of them.
+ for (std::list<std::string>::const_iterator name = names.begin();
+ name != names.end(); ++name) {
+ // Get all definitions.
+ OptionDefContainerPtr defs = getAll(*name);
+ OptionDefContainerPtr other_defs = other.getAll(*name);
+ // Compare sizes. If they hold different number of definitions,
+ // they are unequal.
+ if (defs->size() != defs->size()) {
+ return (false);
+ }
+ // For each option definition, try to find one in the other object.
+ for (OptionDefContainer::const_iterator def = defs->begin();
+ def != defs->end(); ++def) {
+ OptionDefinitionPtr
+ other_def = other.get(*name, (*def)->getCode());
+ // Actually compare them.
+ if (!other_def || (*other_def != **def)) {
+ return (false);
+ }
+ }
+ }
+
+ // All checks passed.
+ return (true);
+}
+
+void
+CfgOptionDef::add(const OptionDefinitionPtr& def) {
+ // Option definition being added must be a valid pointer.
+ if (!def) {
+ isc_throw(MalformedOptionDefinition,
+ "option definition must not be NULL");
+ }
+ const std::string& option_space = def->getOptionSpaceName();
+
+ // Must not duplicate an option definition.
+ if (get(option_space, def->getCode())) {
+ isc_throw(DuplicateOptionDefinition, "option definition with code '"
+ << def->getCode() << "' already exists in option"
+ " space '" << option_space << "'");
+ } else if (get(option_space, def->getName())) {
+ isc_throw(DuplicateOptionDefinition, "option definition with name '"
+ << def->getName() << "' already exists in option"
+ " space '" << option_space << "'");
+
+ // Must not override standard option definition.
+ } else if (LibDHCP::getOptionDef(option_space, def->getCode())) {
+ isc_throw(BadValue, "unable to override definition of option '"
+ << def->getCode() << "' in standard option space '"
+ << option_space << "'");
+ } else if (LibDHCP::getOptionDef(option_space, def->getName())) {
+ isc_throw(BadValue, "unable to override definition of option '"
+ << def->getName() << "' in standard option space '"
+ << option_space << "'");
+ }
+ // Add the definition.
+ option_definitions_.addItem(def);
+}
+
+OptionDefContainerPtr
+CfgOptionDef::getAll(const std::string& option_space) const {
+ /// @todo Does option space require any validation here?
+ return (option_definitions_.getItems(option_space));
+}
+
+OptionDefinitionPtr
+CfgOptionDef::get(const std::string& option_space,
+ const uint16_t option_code) const {
+ // Get the pointer to collection of the option definitions that belong
+ // to the particular option space.
+ OptionDefContainerPtr defs = getAll(option_space);
+ // If there are any option definitions for this option space, get the
+ // one that has the specified option code.
+ if (defs && !defs->empty()) {
+ const OptionDefContainerTypeIndex& idx = defs->get<1>();
+ const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
+ // If there is more than one definition matching the option code,
+ // return the first one. In fact, it shouldn't happen that we have
+ // more than one because we check for duplicates when we add them.
+ if (std::distance(range.first, range.second) > 0) {
+ return (*range.first);
+ }
+ }
+ // Nothing found. Return NULL pointer.
+ return (OptionDefinitionPtr());
+}
+
+OptionDefinitionPtr
+CfgOptionDef::get(const std::string& option_space,
+ const std::string& option_name) const {
+ // Get the pointer to collection of the option definitions that belong
+ // to the particular option space.
+ OptionDefContainerPtr defs = getAll(option_space);
+ // If there are any option definitions for this option space, get the
+ // one that has the specified option name.
+ if (defs && !defs->empty()) {
+ const OptionDefContainerNameIndex& idx = defs->get<2>();
+ const OptionDefContainerNameRange& range = idx.equal_range(option_name);
+ // If there is more than one definition matching the option name,
+ // return the first one. In fact, it shouldn't happen that we have
+ // more than one because we check for duplicates when we add them.
+ if (std::distance(range.first, range.second) > 0) {
+ return (*range.first);
+ }
+ }
+ // Nothing found. Return NULL pointer.
+ return (OptionDefinitionPtr());
+}
+
+uint64_t
+CfgOptionDef::del(const uint64_t id) {
+ return (option_definitions_.deleteItems(id));
+}
+
+ElementPtr
+CfgOptionDef::toElement() const {
+ return (toElementWithMetadata(false));
+}
+
+ElementPtr
+CfgOptionDef::toElementWithMetadata(const bool include_metadata) const {
+ // option-defs value is a list of maps
+ ElementPtr result = Element::createList();
+ // Iterate through the container by names and definitions
+ const std::list<std::string>& names =
+ option_definitions_.getOptionSpaceNames();
+ for (std::list<std::string>::const_iterator name = names.begin();
+ name != names.end(); ++name) {
+ OptionDefContainerPtr defs = getAll(*name);
+ for (OptionDefContainer::const_iterator def = defs->begin();
+ def != defs->end(); ++def) {
+ // Get and fill the map for this definition
+ ElementPtr map = Element::createMap();
+ // Set user context
+ (*def)->contextToElement(map);
+ // Set space from parent iterator
+ map->set("space", Element::create(*name));
+ // Set required items: name, code and type
+ map->set("name", Element::create((*def)->getName()));
+ map->set("code", Element::create((*def)->getCode()));
+ std::string data_type =
+ OptionDataTypeUtil::getDataTypeName((*def)->getType());
+ map->set("type", Element::create(data_type));
+ // Set the array type
+ bool array_type = (*def)->getArrayType();
+ map->set("array", Element::create(array_type));
+ // Set the encapsulate space
+ std::string encapsulates = (*def)->getEncapsulatedSpace();
+ map->set("encapsulate", Element::create(encapsulates));
+ // Set the record field types
+ OptionDefinition::RecordFieldsCollection fields =
+ (*def)->getRecordFields();
+ if (!fields.empty()) {
+ std::ostringstream oss;
+ for (OptionDefinition::RecordFieldsCollection::const_iterator
+ field = fields.begin();
+ field != fields.end(); ++field) {
+ if (field != fields.begin()) {
+ oss << ", ";
+ }
+ oss << OptionDataTypeUtil::getDataTypeName(*field);
+ }
+ map->set("record-types", Element::create(oss.str()));
+ } else {
+ map->set("record-types", Element::create(std::string()));
+ }
+
+ // Include metadata if requested.
+ if (include_metadata) {
+ map->set("metadata", (*def)->getMetadata());
+ }
+
+ // Push on the list
+ result->add(map);
+ }
+ }
+ return (result);
+}
+
+void
+CfgOptionDef::merge(CfgOptionDef& other) {
+ // The definitions in "other" are presumed to be valid and
+ // not in conflict with standard definitions.
+ if (other.getContainer().getOptionSpaceNames().empty()) {
+ // Nothing to merge, don't waste cycles.
+ return;
+ }
+
+ // Iterate over this config's definitions in each space.
+ // If either a definition's name or code already exist in
+ // that space in "other", skip it. Otherwise, add it to "other".
+ for (auto space : option_definitions_.getOptionSpaceNames()) {
+ for (auto my_def : *(getAll(space))) {
+ if ((other.get(space, my_def->getName())) ||
+ (other.get(space, my_def->getCode()))) {
+ // Already in "other" so skip it.
+ continue;
+ }
+
+ // Not in "other" so add it.
+ other.add(my_def);
+ }
+ }
+
+ // Replace the current definitions with the merged set.
+ other.copyTo(*this);
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc