diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 11:36:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 11:36:04 +0000 |
commit | 040eee1aa49b49df4698d83a05af57c220127fd1 (patch) | |
tree | f635435954e6ccde5eee9893889e24f30ca68346 /src/lib/dhcpsrv/cfg_option_def.cc | |
parent | Initial commit. (diff) | |
download | isc-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.cc | 261 |
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 |