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
18using namespace isc::data;
19
20namespace isc {
21namespace dhcp {
22
23bool
25 return ((persistent_ == other.persistent_) &&
27 (space_name_ == other.space_name_) &&
28 option_->equals(other.option_));
29}
30
32}
33
34bool
36 return (options_.empty() && vendor_options_.empty());
37}
38
39bool
40CfgOption::equals(const CfgOption& other) const {
41 return (options_.equals(other.options_) &&
42 vendor_options_.equals(other.vendor_options_));
43}
44
45void
46CfgOption::add(const OptionPtr& option, const bool persistent,
47 const std::string& option_space) {
48 add(OptionDescriptor(option, persistent), option_space);
49}
50
51void
52CfgOption::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
69std::list<std::string>
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
84void
86 // Merge non-vendor options.
87 mergeInternal(options_, other.options_);
88 // Merge vendor options.
89 mergeInternal(vendor_options_, other.vendor_options_);
90}
91
92void
94 // Remove any existing data in the destination.
95 other.options_.clearItems();
96 other.vendor_options_.clearItems();
97 mergeTo(other);
98}
99
100void
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
108void
109CfgOption::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
120void
121CfgOption::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
146template <typename Selector>
147void
148CfgOption::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
183CfgOption::getAll(const std::string& option_space) const {
184 return (options_.getItems(option_space));
185}
186
188CfgOption::getAll(const uint32_t vendor_id) const {
189 return (vendor_options_.getItems(vendor_id));
190}
191
194 // option-data value is a list of maps
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)
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();
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
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:223
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:268
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:263
Represents option data configuration for the DHCP server.
Definition: cfg_option.h:248
void encapsulate()
Appends encapsulated options to top-level options.
Definition: cfg_option.cc:101
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
Definition: cfg_option.cc:193
void add(const OptionPtr &option, const bool persistent, const std::string &option_space)
Adds instance of the option to the configuration.
Definition: cfg_option.cc:46
bool empty() const
Indicates the object is empty.
Definition: cfg_option.cc:35
void mergeTo(CfgOption &other) const
Merges this configuration to another configuration.
Definition: cfg_option.cc:85
void copyTo(CfgOption &other) const
Copies this configuration to another configuration.
Definition: cfg_option.cc:93
CfgOption()
default constructor
Definition: cfg_option.cc:31
std::list< std::string > getVendorIdsSpaceNames() const
Returns a list of option space names for configured vendor ids.
Definition: cfg_option.cc:70
OptionContainerPtr getAll(const std::string &option_space) const
Returns all options for the specified option space.
Definition: cfg_option.cc:183
bool equals(const CfgOption &other) const
Check if configuration is equal to other configuration.
Definition: cfg_option.cc:40
std::list< uint32_t > getVendorIds() const
Returns a list of all configured vendor identifiers.
Definition: cfg_option.h:419
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition: libdhcp++.cc:144
static OptionDefinitionPtr getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id, const uint16_t code)
Returns vendor option definition for a given vendor-id and code.
Definition: libdhcp++.cc:184
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
Definition: libdhcp++.cc:916
static OptionDefinitionPtr getRuntimeOptionDef(const std::string &space, const uint16_t code)
Returns runtime (non-standard) option definition by space and option code.
Definition: libdhcp++.cc:205
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Definition: libdhcp++.cc:265
Option descriptor.
Definition: cfg_option.h:35
OptionPtr option_
Option instance.
Definition: cfg_option.h:38
std::string space_name_
Option space name.
Definition: cfg_option.h:70
bool equals(const OptionDescriptor &other) const
Checks if the one descriptor is equal to another.
Definition: cfg_option.cc:24
std::string formatted_value_
Option value in textual (CSV) format.
Definition: cfg_option.h:59
bool persistent_
Persistence flag.
Definition: cfg_option.h:44
void addItem(const ItemType &item, const Selector &option_space)
Adds a new item to the option_space.
bool empty() const
Indicates the container is empty.
void clearItems()
Remove all items from the container.
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.
bool equals(const OptionSpaceContainer &other) const
Check if two containers are equal.
static bool validateName(const std::string &name)
Checks that the provided option space name is valid.
Definition: option_space.cc:26
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:67
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:22
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
OptionContainer::nth_index< 1 >::type OptionContainerTypeIndex
Type of the index #1 - option type.
Definition: cfg_option.h:208
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
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
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
Definition: cfg_option.h:206
boost::shared_ptr< Option > OptionPtr
Definition: option.h:38
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 ('hex') format.
Definition: base_n.cc:461
Defines the logger used by the top-level component of kea-dhcp-ddns.
#define DHCP4_OPTION_SPACE
Definition: option_space.h:16
#define DHCP6_OPTION_SPACE
Definition: option_space.h:17