Kea  1.5.0
cfg_option.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2018 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 
9 #include <dhcp/libdhcp++.h>
10 #include <dhcpsrv/cfg_option.h>
11 #include <dhcp/dhcp6.h>
12 #include <dhcp/option_space.h>
13 #include <util/encode/hex.h>
14 #include <string>
15 #include <sstream>
16 #include <vector>
17 
18 using namespace isc::data;
19 
20 namespace isc {
21 namespace dhcp {
22 
23 bool
24 OptionDescriptor::equals(const OptionDescriptor& other) const {
25  return ((persistent_ == other.persistent_) &&
26  (formatted_value_ == other.formatted_value_) &&
27  (space_name_ == other.space_name_) &&
28  option_->equals(other.option_));
29 }
30 
31 CfgOption::CfgOption() {
32 }
33 
34 bool
35 CfgOption::empty() const {
36  return (options_.empty() && vendor_options_.empty());
37 }
38 
39 bool
40 CfgOption::equals(const CfgOption& other) const {
41  return (options_.equals(other.options_) &&
42  vendor_options_.equals(other.vendor_options_));
43 }
44 
45 void
46 CfgOption::add(const OptionPtr& option, const bool persistent,
47  const std::string& option_space) {
48  add(OptionDescriptor(option, persistent), option_space);
49 }
50 
51 void
52 CfgOption::add(const OptionDescriptor& desc, const std::string& option_space) {
53  if (!desc.option_) {
54  isc_throw(isc::BadValue, "option being configured must not be NULL");
55 
56  } else if (!OptionSpace::validateName(option_space)) {
57  isc_throw(isc::BadValue, "invalid option space name: '"
58  << option_space << "'");
59  }
60 
61  const uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(option_space);
62  if (vendor_id) {
63  vendor_options_.addItem(desc, vendor_id);
64  } else {
65  options_.addItem(desc, option_space);
66  }
67 }
68 
69 std::list<std::string>
70 CfgOption::getVendorIdsSpaceNames() const {
71  std::list<uint32_t> ids = getVendorIds();
72  std::list<std::string> names;
73  for (std::list<uint32_t>::const_iterator id = ids.begin();
74  id != ids.end(); ++id) {
75  std::ostringstream s;
76  // Vendor space name is constructed as "vendor-XYZ" where XYZ is an
77  // uint32_t value, without leading zeros.
78  s << "vendor-" << *id;
79  names.push_back(s.str());
80  }
81  return (names);
82 }
83 
84 void
85 CfgOption::mergeTo(CfgOption& other) const {
86  // Merge non-vendor options.
87  mergeInternal(options_, other.options_);
88  // Merge vendor options.
89  mergeInternal(vendor_options_, other.vendor_options_);
90 }
91 
92 void
93 CfgOption::copyTo(CfgOption& other) const {
94  // Remove any existing data in the destination.
95  other.options_.clearItems();
96  other.vendor_options_.clearItems();
97  mergeTo(other);
98 }
99 
100 void
101 CfgOption::encapsulate() {
102  // Append sub-options to the top level "dhcp4" option space.
103  encapsulateInternal(DHCP4_OPTION_SPACE);
104  // Append sub-options to the top level "dhcp6" option space.
105  encapsulateInternal(DHCP6_OPTION_SPACE);
106 }
107 
108 void
109 CfgOption::encapsulateInternal(const std::string& option_space) {
110  // Get all options for the particular option space.
111  OptionContainerPtr options = getAll(option_space);
112  // For each option in the option space we will append sub-options
113  // from the option spaces they encapsulate.
114  for (OptionContainer::const_iterator opt = options->begin();
115  opt != options->end(); ++opt) {
116  encapsulateInternal(opt->option_);
117  }
118 }
119 
120 void
121 CfgOption::encapsulateInternal(const OptionPtr& option) {
122  // Get encapsulated option space for the option.
123  const std::string& encap_space = option->getEncapsulatedSpace();
124  // Empty value means that no option space is encapsulated.
125  if (!encap_space.empty()) {
126  // Retrieve all options from the encapsulated option space.
127  OptionContainerPtr encap_options = getAll(encap_space);
128  for (OptionContainer::const_iterator encap_opt =
129  encap_options->begin(); encap_opt != encap_options->end();
130  ++encap_opt) {
131  // Add sub-option if there isn't one added already.
132  if (!option->getOption(encap_opt->option_->getType())) {
133  option->addOption(encap_opt->option_);
134  }
135  // This is a workaround for preventing infinite recursion when
136  // trying to encapsulate options created with default global option
137  // spaces.
138  if (encap_space != DHCP4_OPTION_SPACE &&
139  encap_space != DHCP6_OPTION_SPACE) {
140  encapsulateInternal(encap_opt->option_);
141  }
142  }
143  }
144 }
145 
146 template <typename Selector>
147 void
148 CfgOption::mergeInternal(const OptionSpaceContainer<OptionContainer,
149  OptionDescriptor, Selector>& src_container,
150  OptionSpaceContainer<OptionContainer,
151  OptionDescriptor, Selector>& dest_container) const {
152  // Get all option spaces used in source container.
153  std::list<Selector> selectors = src_container.getOptionSpaceNames();
154 
155  // For each space in the source container retrieve the actual options and
156  // match them with the options held in the destination container under
157  // the same space.
158  for (typename std::list<Selector>::const_iterator it = selectors.begin();
159  it != selectors.end(); ++it) {
160  // Get all options in the destination container for the particular
161  // option space.
162  OptionContainerPtr dest_all = dest_container.getItems(*it);
163  OptionContainerPtr src_all = src_container.getItems(*it);
164  // For each option under this option space check if there is a
165  // corresponding option in the destination container. If not,
166  // add one.
167  for (OptionContainer::const_iterator src_opt = src_all->begin();
168  src_opt != src_all->end(); ++src_opt) {
169  const OptionContainerTypeIndex& idx = dest_all->get<1>();
170  const OptionContainerTypeRange& range =
171  idx.equal_range(src_opt->option_->getType());
172  // If there is no such option in the destination container,
173  // add one.
174  if (std::distance(range.first, range.second) == 0) {
175  dest_container.addItem(OptionDescriptor(*src_opt), *it);
176  }
177  }
178  }
179 }
180 
181 
183 CfgOption::getAll(const std::string& option_space) const {
184  return (options_.getItems(option_space));
185 }
186 
188 CfgOption::getAll(const uint32_t vendor_id) const {
189  return (vendor_options_.getItems(vendor_id));
190 }
191 
193 CfgOption::toElement() const {
194  // option-data value is a list of maps
195  ElementPtr result = Element::createList();
196  // Iterate first on options using space names
197  const std::list<std::string>& names = options_.getOptionSpaceNames();
198  for (std::list<std::string>::const_iterator name = names.begin();
199  name != names.end(); ++name) {
200  OptionContainerPtr opts = getAll(*name);
201  for (OptionContainer::const_iterator opt = opts->begin();
202  opt != opts->end(); ++opt) {
203  // Get and fill the map for this option
205  // Set user context
206  opt->contextToElement(map);
207  // Set space from parent iterator
208  map->set("space", Element::create(*name));
209  // Set the code
210  uint16_t code = opt->option_->getType();
211  map->set("code", Element::create(code));
212  // Set the name (always for standard options else when asked for)
213  OptionDefinitionPtr def = LibDHCP::getOptionDef(*name, code);
214  if (!def) {
215  def = LibDHCP::getRuntimeOptionDef(*name, code);
216  }
217  if (!def) {
218  def = LibDHCP::getLastResortOptionDef(*name, code);
219  }
220  if (def) {
221  map->set("name", Element::create(def->getName()));
222  }
223  // Set the data item
224  if (!opt->formatted_value_.empty()) {
225  map->set("csv-format", Element::create(true));
226  map->set("data", Element::create(opt->formatted_value_));
227  } else {
228  map->set("csv-format", Element::create(false));
229  std::vector<uint8_t> bin = opt->option_->toBinary();
230  std::string repr = util::encode::encodeHex(bin);
231  map->set("data", Element::create(repr));
232  }
233  // Set the persistency flag
234  map->set("always-send", Element::create(opt->persistent_));
235  // Push on the list
236  result->add(map);
237  }
238  }
239  // Iterate first on vendor_options using vendor ids
240  const std::list<uint32_t>& ids = vendor_options_.getOptionSpaceNames();
241  for (std::list<uint32_t>::const_iterator id = ids.begin();
242  id != ids.end(); ++id) {
243  OptionContainerPtr opts = getAll(*id);
244  for (OptionContainer::const_iterator opt = opts->begin();
245  opt != opts->end(); ++opt) {
246  // Get and fill the map for this option
248  // Set user context
249  opt->contextToElement(map);
250  // Set space from parent iterator
251  std::ostringstream oss;
252  oss << "vendor-" << *id;
253  map->set("space", Element::create(oss.str()));
254  // Set the code
255  uint16_t code = opt->option_->getType();
256  map->set("code", Element::create(code));
257  // Set the name
258  Option::Universe universe = opt->option_->getUniverse();
259  OptionDefinitionPtr def =
260  LibDHCP::getVendorOptionDef(universe, *id, code);
261  if (!def) {
262  // vendor-XXX space is in oss
263  def = LibDHCP::getRuntimeOptionDef(oss.str(), code);
264  }
265  if (def) {
266  map->set("name", Element::create(def->getName()));
267  }
268  // Set the data item
269  if (!opt->formatted_value_.empty()) {
270  map->set("csv-format", Element::create(true));
271  map->set("data", Element::create(opt->formatted_value_));
272  } else {
273  map->set("csv-format", Element::create(false));
274  std::vector<uint8_t> bin = opt->option_->toBinary();
275  std::string repr = util::encode::encodeHex(bin);
276  map->set("data", Element::create(repr));
277  }
278  // Set the persistency flag
279  map->set("always-send", Element::create(opt->persistent_));
280  // Push on the list
281  result->add(map);
282  }
283  }
284  return (result);
285 }
286 
287 } // namespace dhcp
288 } // namespace isc
isc::dhcp::OptionContainerPtr
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
Definition: cfg_option.h:206
option_space.h
isc::dhcp::OptionDefinitionPtr
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
Definition: option_definition.h:51
libdhcp++.h
DHCP6_OPTION_SPACE
#define DHCP6_OPTION_SPACE
Definition: option_space.h:17
isc::data
Definition: cfg_to_element.h:25
isc::dhcp::CfgOption
Represents option data configuration for the DHCP server.
Definition: cfg_option.h:248
isc::data::Element::createMap
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:268
isc::dhcp::OptionDescriptor::persistent_
bool persistent_
Persistence flag.
Definition: cfg_option.h:44
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
hex.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::dhcp::OptionContainer
boost::multi_index_container< OptionDescriptor, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::hashed_non_unique< KeyFromKeyExtractor< boost::multi_index::const_mem_fun< Option, uint16_t, &Option::getType >, boost::multi_index::member< OptionDescriptor, OptionPtr, &OptionDescriptor::option_ > > >, boost::multi_index::hashed_non_unique< boost::multi_index::member< OptionDescriptor, bool, &OptionDescriptor::persistent_ > > >> OptionContainer
Multi index container for DHCP option descriptors.
Definition: cfg_option.h:203
isc::dhcp::OptionContainerTypeRange
std::pair< OptionContainerTypeIndex::const_iterator, OptionContainerTypeIndex::const_iterator > OptionContainerTypeRange
Pair of iterators to represent the range of options having the same option type value.
Definition: cfg_option.h:213
isc::dhcp::OptionContainerTypeIndex
OptionContainer::nth_index< 1 >::type OptionContainerTypeIndex
Type of the index #1 - option type.
Definition: cfg_option.h:208
cfg_option.h
DHCP4_OPTION_SPACE
#define DHCP4_OPTION_SPACE
Definition: option_space.h:16
isc::dhcp::OptionSpaceContainer::clearItems
void clearItems()
Remove all items from the container.
Definition: option_space_container.h:87
isc::data::Element::createList
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:263
dhcp6.h
isc::dhcp::OptionDescriptor::space_name_
std::string space_name_
Option space name.
Definition: cfg_option.h:70
isc::dhcp::OptionDescriptor::option_
OptionPtr option_
Option instance.
Definition: cfg_option.h:38
isc::util::encode::encodeHex
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 ('hex') format.
Definition: base_n.cc:461
isc::dhcp::OptionPtr
boost::shared_ptr< Option > OptionPtr
Definition: option.h:37
isc::dhcp::OptionDescriptor
Option descriptor.
Definition: cfg_option.h:35
isc::dhcp::Option::Universe
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:67
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
isc::data::Element::create
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:223
isc::dhcp::OptionDescriptor::formatted_value_
std::string formatted_value_
Option value in textual (CSV) format.
Definition: cfg_option.h:59