Kea 2.7.1
cfg_option_def.cc
Go to the documentation of this file.
1// Copyright (C) 2014-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#include <dhcp/libdhcp++.h>
11#include <dhcp/option_space.h>
13#include <sstream>
14
15using namespace isc::data;
16
17namespace isc {
18namespace dhcp {
19
20void
22 // Remove any existing option definitions from the destination.
23 new_config.option_definitions_.clearItems();
24 const std::list<std::string>& names =
25 option_definitions_.getOptionSpaceNames();
26 for (auto const& name : names) {
27 OptionDefContainerPtr defs = getAll(name);
28 for (auto const& def : *defs) {
29 OptionDefinitionPtr new_def =
31 new_config.add(new_def);
32 }
33 }
34}
35
36bool
38 // Get our option space names.
39 const std::list<std::string>& names = option_definitions_.getOptionSpaceNames();
40 // Get option space names held by the other object.
41 const std::list<std::string>&
42 other_names = other.option_definitions_.getOptionSpaceNames();
43 // Compare that sizes are the same. If they hold different number of
44 // option space names the objects are not equal.
45 if (names.size() != other_names.size()) {
46 return (false);
47 }
48 // Iterate over all option space names and get the definitions for each
49 // of them.
50 for (auto const& name : names) {
51 // Get all definitions.
52 OptionDefContainerPtr defs = getAll(name);
53 OptionDefContainerPtr other_defs = other.getAll(name);
54 // Compare sizes. If they hold different number of definitions,
55 // they are unequal.
56 if (defs->size() != defs->size()) {
57 return (false);
58 }
59 // For each option definition, try to find one in the other object.
60 for (auto const& def : *defs) {
61 OptionDefinitionPtr other_def = other.get(name, def->getCode());
62 // Actually compare them.
63 if (!other_def || (*other_def != *def)) {
64 return (false);
65 }
66 }
67 }
68
69 // All checks passed.
70 return (true);
71}
72
73void
75 // Option definition being added must be a valid pointer.
76 if (!def) {
78 "option definition must not be NULL");
79 }
80 const std::string& option_space = def->getOptionSpaceName();
81
82 // Must not duplicate an option definition.
83 if (get(option_space, def->getCode())) {
84 isc_throw(DuplicateOptionDefinition, "option definition with code '"
85 << def->getCode() << "' already exists in option"
86 " space '" << option_space << "'");
87 } else if (get(option_space, def->getName())) {
88 isc_throw(DuplicateOptionDefinition, "option definition with name '"
89 << def->getName() << "' already exists in option"
90 " space '" << option_space << "'");
91
92 // Must not override standard option definition.
93 } else if (LibDHCP::getOptionDef(option_space, def->getCode())) {
94 isc_throw(BadValue, "unable to override definition of option '"
95 << def->getCode() << "' in standard option space '"
96 << option_space << "'");
97 } else if (LibDHCP::getOptionDef(option_space, def->getName())) {
98 isc_throw(BadValue, "unable to override definition of option '"
99 << def->getName() << "' in standard option space '"
100 << option_space << "'");
101 }
102 // Add the definition.
103 option_definitions_.addItem(def);
104}
105
107CfgOptionDef::getAll(const std::string& option_space) const {
109 return (option_definitions_.getItems(option_space));
110}
111
113CfgOptionDef::get(const std::string& option_space,
114 const uint16_t option_code) const {
115 // Get the pointer to collection of the option definitions that belong
116 // to the particular option space.
117 OptionDefContainerPtr defs = getAll(option_space);
118 // If there are any option definitions for this option space, get the
119 // one that has the specified option code.
120 if (defs && !defs->empty()) {
121 const OptionDefContainerTypeIndex& idx = defs->get<1>();
122 const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
123 // If there is more than one definition matching the option code,
124 // return the first one. In fact, it shouldn't happen that we have
125 // more than one because we check for duplicates when we add them.
126 if (std::distance(range.first, range.second) > 0) {
127 return (*range.first);
128 }
129 }
130 // Nothing found. Return NULL pointer.
131 return (OptionDefinitionPtr());
132}
133
135CfgOptionDef::get(const std::string& option_space,
136 const std::string& option_name) const {
137 // Get the pointer to collection of the option definitions that belong
138 // to the particular option space.
139 OptionDefContainerPtr defs = getAll(option_space);
140 // If there are any option definitions for this option space, get the
141 // one that has the specified option name.
142 if (defs && !defs->empty()) {
143 const OptionDefContainerNameIndex& idx = defs->get<2>();
144 const OptionDefContainerNameRange& range = idx.equal_range(option_name);
145 // If there is more than one definition matching the option name,
146 // return the first one. In fact, it shouldn't happen that we have
147 // more than one because we check for duplicates when we add them.
148 if (std::distance(range.first, range.second) > 0) {
149 return (*range.first);
150 }
151 }
152 // Nothing found. Return NULL pointer.
153 return (OptionDefinitionPtr());
154}
155
156uint64_t
157CfgOptionDef::del(const uint64_t id) {
158 return (option_definitions_.deleteItems(id));
159}
160
163 return (toElementWithMetadata(false));
164}
165
167CfgOptionDef::toElementWithMetadata(const bool include_metadata) const {
168 // option-defs value is a list of maps
170 // Iterate through the container by names and definitions
171 const std::list<std::string>& names =
172 option_definitions_.getOptionSpaceNames();
173 for (auto const& name : names) {
174 OptionDefContainerPtr defs = getAll(name);
175 for (auto const& def : *defs) {
176 // Get and fill the map for this definition
178 // Set user context
179 def->contextToElement(map);
180 // Set space from parent iterator
181 map->set("space", Element::create(name));
182 // Set required items: name, code and type
183 map->set("name", Element::create(def->getName()));
184 map->set("code", Element::create(def->getCode()));
185 std::string data_type =
187 map->set("type", Element::create(data_type));
188 // Set the array type
189 bool array_type = def->getArrayType();
190 map->set("array", Element::create(array_type));
191 // Set the encapsulate space
192 std::string encapsulates = def->getEncapsulatedSpace();
193 map->set("encapsulate", Element::create(encapsulates));
194 // Set the record field types
196 def->getRecordFields();
197 if (!fields.empty()) {
198 std::ostringstream oss;
199 bool first = true;
200 for (auto const& field : fields) {
201 if (!first) {
202 oss << ", ";
203 } else {
204 first = false;
205 }
207 }
208 map->set("record-types", Element::create(oss.str()));
209 } else {
210 map->set("record-types", Element::create(std::string()));
211 }
212
213 // Include metadata if requested.
214 if (include_metadata) {
215 map->set("metadata", def->getMetadata());
216 }
217
218 // Push on the list
219 result->add(map);
220 }
221 }
222 return (result);
223}
224
225void
227 // The definitions in "other" are presumed to be valid and
228 // not in conflict with standard definitions.
229 if (other.getContainer().getOptionSpaceNames().empty()) {
230 // Nothing to merge, don't waste cycles.
231 return;
232 }
233
234 // Iterate over this config's definitions in each space.
235 // If either a definition's name or code already exist in
236 // that space in "other", skip it. Otherwise, add it to "other".
237 for (auto const& space : option_definitions_.getOptionSpaceNames()) {
238 for (auto const& tmp_def : *(getAll(space))) {
239 if ((other.get(space, tmp_def->getName())) ||
240 (other.get(space, tmp_def->getCode()))) {
241 // Already in "other" so skip it.
242 continue;
243 }
244
245 // Not in "other" so add it.
246 other.add(tmp_def);
247 }
248 }
249
250 // Replace the current definitions with the merged set.
251 other.copyTo(*this);
252}
253
254} // end of namespace isc::dhcp
255} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
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 ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
Represents option definitions used by the DHCP server.
void add(const OptionDefinitionPtr &def)
Add new option definition.
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
isc::data::ElementPtr toElementWithMetadata(const bool include_metadata) const
Unparse a configuration object with optionally including the metadata.
uint64_t del(const uint64_t id)
Deletes all option definitions having a given database id.
OptionDefContainerPtr getAll(const std::string &option_space) const
Return option definitions for particular option space.
bool equals(const CfgOptionDef &other) const
Check if configuration is equal to other configuration.
void merge(CfgOptionDef &other)
Merges specified option definitions from a configuration into this configuration.
OptionDefinitionPtr get(const std::string &option_space, const uint16_t option_code) const
Return option definition for a particular option space and code.
void copyTo(CfgOptionDef &new_config) const
Copies this configuration to a new configuration.
Exception to be thrown when the particular option definition duplicates existing option definition.
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition libdhcp++.cc:128
Exception to be thrown when option definition is invalid.
static const std::string & getDataTypeName(const OptionDataType data_type)
Return option data type name from the data type enumerator.
void addItem(const OptionDefinitionPtr &def)
Adds a new option definition to the container.
Base class representing a DHCP option definition.
std::vector< OptionDataType > RecordFieldsCollection
List of fields within the record.
uint64_t deleteItems(const uint64_t id)
Remove all options or option definitions with a given database identifier.
std::list< Selector > getOptionSpaceNames() const
Get a list of existing option spaces.
ItemsContainerPtr getItems(const Selector &option_space) const
Get all items for the particular option space.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
std::pair< OptionDefContainerNameIndex::const_iterator, OptionDefContainerNameIndex::const_iterator > OptionDefContainerNameRange
Pair of iterators to represent the range of options definitions having the same option name.
OptionDefContainer::nth_index< 2 >::type OptionDefContainerNameIndex
Type of the index #2 - option name.
std::pair< OptionDefContainerTypeIndex::const_iterator, OptionDefContainerTypeIndex::const_iterator > OptionDefContainerTypeRange
Pair of iterators to represent the range of options definitions having the same option type value.
OptionDefContainer::nth_index< 1 >::type OptionDefContainerTypeIndex
Type of the index #1 - option type.
boost::shared_ptr< OptionDefContainer > OptionDefContainerPtr
Pointer to an option definition container.
Defines the logger used by the top-level component of kea-lfc.