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