Kea 2.5.8
cfg_option.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
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/encode.h>
14#include <boost/algorithm/string/split.hpp>
15#include <boost/algorithm/string/classification.hpp>
16#include <boost/make_shared.hpp>
17#include <string>
18#include <sstream>
19#include <vector>
20
21using namespace isc::data;
22
23namespace isc {
24namespace dhcp {
25
27OptionDescriptor::create(const OptionPtr& opt, bool persist, bool cancel,
28 const std::string& formatted_value,
29 ConstElementPtr user_context) {
30 return (boost::make_shared<OptionDescriptor>(opt, persist, cancel,
31 formatted_value,
32 user_context));
33}
34
36OptionDescriptor::create(bool persist, bool cancel) {
37 return (boost::make_shared<OptionDescriptor>(persist, cancel));
38}
39
42 return (boost::make_shared<OptionDescriptor>(desc));
43}
44
45bool
47 return ((persistent_ == other.persistent_) &&
48 (cancelled_ == other.cancelled_) &&
50 (space_name_ == other.space_name_) &&
51 option_->equals(other.option_));
52}
53
55 : encapsulated_(false) {
56}
57
58bool
60 return (options_.empty() && vendor_options_.empty());
61}
62
63bool
64CfgOption::equals(const CfgOption& other) const {
65 return (options_.equals(other.options_) &&
66 vendor_options_.equals(other.vendor_options_));
67}
68
69void
71 const bool persistent,
72 const bool cancelled,
73 const std::string& option_space,
74 const uint64_t id) {
75 OptionDescriptor desc(option, persistent, cancelled);
76 if (id > 0) {
77 desc.setId(id);
78 }
79 add(desc, option_space);
80}
81
82void
83CfgOption::add(const OptionDescriptor& desc, const std::string& option_space) {
84 if (!desc.option_) {
85 isc_throw(isc::BadValue, "option being configured must not be NULL");
86
87 } else if (!OptionSpace::validateName(option_space)) {
88 isc_throw(isc::BadValue, "invalid option space name: '"
89 << option_space << "'");
90 }
91
92 const uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(option_space);
93 if (vendor_id) {
94 vendor_options_.addItem(desc, vendor_id);
95 } else {
96 options_.addItem(desc, option_space);
97 }
98}
99
100void
101CfgOption::replace(const OptionDescriptor& desc, const std::string& option_space) {
102 if (!desc.option_) {
103 isc_throw(isc::BadValue, "option being replaced must not be NULL");
104 }
105
106 // Check for presence of options.
107 OptionContainerPtr options = getAll(option_space);
108 if (!options) {
109 isc_throw(isc::BadValue, "option space " << option_space
110 << " does not exist");
111 }
112
113 // Find the option we want to replace.
114 OptionContainerTypeIndex& idx = options->get<1>();
115 auto const& od_itr = idx.find(desc.option_->getType());
116 if (od_itr == idx.end()) {
117 isc_throw(isc::BadValue, "cannot replace option: "
118 << option_space << ":" << desc.option_->getType()
119 << ", it does not exist");
120 }
121
122 idx.replace(od_itr, desc);
123}
124
125std::list<std::string>
127 std::list<uint32_t> ids = getVendorIds();
128 std::list<std::string> names;
129 for (auto const& id : ids) {
130 std::ostringstream s;
131 // Vendor space name is constructed as "vendor-XYZ" where XYZ is an
132 // uint32_t value, without leading zeros.
133 s << "vendor-" << id;
134 names.push_back(s.str());
135 }
136 return (names);
137}
138
139void
141 // First we merge our options into other.
142 // This adds my options that are not
143 // in other, to other (i.e we skip over
144 // duplicates).
145 mergeTo(other);
146
147 // Create option instances based on the given definitions.
148 other.createOptions(cfg_def);
149
150 // Next we copy "other" on top of ourself.
151 other.copyTo(*this);
152
153 // If we copied new options we may need to populate the
154 // sub-options into the upper level options. The server
155 // expects that the top-level options have suitable
156 // suboptions appended.
157 encapsulate();
158}
159
160void
162 // Iterate over all the option descriptors in
163 // all the spaces and instantiate the options
164 // based on the given definitions.
165 for (auto const& space : getOptionSpaceNames()) {
166 for (auto opt_desc : *(getAll(space))) {
167 if (createDescriptorOption(cfg_def, space, opt_desc)) {
168 // Option was recreated, let's replace the descriptor.
169 replace(opt_desc, space);
170 }
171 }
172 }
173}
174
175bool
176CfgOption::createDescriptorOption(CfgOptionDefPtr cfg_def, const std::string& space,
177 OptionDescriptor& opt_desc) {
178 if (!opt_desc.option_) {
180 "validateCreateOption: descriptor has no option instance");
181 }
182
183 Option::Universe universe = opt_desc.option_->getUniverse();
184 uint16_t code = opt_desc.option_->getType();
185
186 // Find the option's defintion, if it has one.
187 // First, check for a standard definition.
189
190 // If there is no standard definition but the option is vendor specific,
191 // we should search the definition within the vendor option space.
192 if (!def && (space != DHCP4_OPTION_SPACE) && (space != DHCP6_OPTION_SPACE)) {
193 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
194 if (vendor_id > 0) {
195 def = LibDHCP::getVendorOptionDef(universe, vendor_id, code);
196 }
197 }
198
199 // Still haven't found the definition, so look for custom
200 // definition in the given set of configured definitions
201 if (!def) {
202 def = cfg_def->get(space, code);
203 }
204
205 // Finish with a last resort option definition.
206 if (!def) {
207 def = LibDHCP::getLastResortOptionDef(space, code);
208 }
209
210 std::string& formatted_value = opt_desc.formatted_value_;
211 if (!def) {
212 if (!formatted_value.empty()) {
213 isc_throw(InvalidOperation, "option: " << space << "." << code
214 << " has a formatted value: '" << formatted_value
215 << "' but no option definition");
216 }
217
218 // If there's no definition and no formatted string, we'll
219 // settle for the generic option already in the descriptor.
220 // Indicate no-change by returning false.
221 return (false);
222 }
223
224 try {
225 // Definition found. Let's replace the generic option in
226 // the descriptor with one created based on definition's factory.
227 if (formatted_value.empty()) {
228 // No formatted value, use data stored in the generic option.
229 opt_desc.option_ = def->optionFactory(universe, code, opt_desc.option_->getData());
230 } else {
231 // Spit the value specified in comma separated values format.
232 std::vector<std::string> split_vec;
233 boost::split(split_vec, formatted_value, boost::is_any_of(","));
234 opt_desc.option_ = def->optionFactory(universe, code, split_vec);
235 }
236 } catch (const std::exception& ex) {
237 isc_throw(InvalidOperation, "could not create option: " << space << "." << code
238 << " from data specified, reason: " << ex.what());
239 }
240
241 // Indicate we replaced the definition.
242 return(true);
243}
244
245void
247 // Merge non-vendor options.
248 mergeInternal(options_, other.options_);
249 // Merge vendor options.
250 mergeInternal(vendor_options_, other.vendor_options_);
251}
252
253void
255 // Remove any existing data in the destination.
256 other.options_.clearItems();
257 other.vendor_options_.clearItems();
258 mergeTo(other);
259}
260
261void
263 // Append sub-options to the top level "dhcp4" option space.
264 encapsulateInternal(DHCP4_OPTION_SPACE);
265 // Append sub-options to the top level "dhcp6" option space.
266 encapsulateInternal(DHCP6_OPTION_SPACE);
267 encapsulated_ = true;
268}
269
270void
271CfgOption::encapsulateInternal(const std::string& option_space) {
272 // Get all options for the particular option space.
273 OptionContainerPtr options = getAll(option_space);
274 // For each option in the option space we will append sub-options
275 // from the option spaces they encapsulate.
276 for (auto const& opt : *options) {
277 encapsulateInternal(opt.option_);
278 }
279}
280
281void
282CfgOption::encapsulateInternal(const OptionPtr& option) {
283 // Get encapsulated option space for the option.
284 const std::string& encap_space = option->getEncapsulatedSpace();
285 // Empty value means that no option space is encapsulated.
286 if (!encap_space.empty()) {
287 if (encap_space == DHCP4_OPTION_SPACE || encap_space == DHCP6_OPTION_SPACE) {
288 return;
289 }
290 // Retrieve all options from the encapsulated option space.
291 OptionContainerPtr encap_options = getAll(encap_space);
292 for (auto const& encap_opt : *encap_options) {
293 if (option.get() == encap_opt.option_.get()) {
294 // Avoid recursion by not adding options to themselves.
295 continue;
296 }
297
298 // Add sub-option if there isn't one added already.
299 if (!option->getOption(encap_opt.option_->getType())) {
300 option->addOption(encap_opt.option_);
301 }
302 encapsulateInternal(encap_opt.option_);
303 }
304 }
305}
306
307template <typename Selector>
308void
309CfgOption::mergeInternal(const OptionSpaceContainer<OptionContainer,
310 OptionDescriptor, Selector>& src_container,
311 OptionSpaceContainer<OptionContainer,
312 OptionDescriptor, Selector>& dest_container) const {
313 // Get all option spaces used in source container.
314 std::list<Selector> selectors = src_container.getOptionSpaceNames();
315
316 // For each space in the source container retrieve the actual options and
317 // match them with the options held in the destination container under
318 // the same space.
319 for (auto const& it : selectors) {
320 // Get all options in the destination container for the particular
321 // option space.
322 OptionContainerPtr dest_all = dest_container.getItems(it);
323 OptionContainerPtr src_all = src_container.getItems(it);
324 // For each option under this option space check if there is a
325 // corresponding option in the destination container. If not,
326 // add one.
327 for (auto const& src_opt : *src_all) {
328 const OptionContainerTypeIndex& idx = dest_all->get<1>();
329 const OptionContainerTypeRange& range =
330 idx.equal_range(src_opt.option_->getType());
331 // If there is no such option in the destination container,
332 // add one.
333 if (std::distance(range.first, range.second) == 0) {
334 dest_container.addItem(OptionDescriptor(src_opt), it);
335 }
336 }
337 }
338}
339
341CfgOption::getAll(const std::string& option_space) const {
342 return (options_.getItems(option_space));
343}
344
346CfgOption::getAll(const uint32_t vendor_id) const {
347 return (vendor_options_.getItems(vendor_id));
348}
349
351CfgOption::getAllCombined(const std::string& option_space) const {
352 auto vendor_id = LibDHCP::optionSpaceToVendorId(option_space);
353 if (vendor_id > 0) {
354 return (getAll(vendor_id));
355 }
356 return (getAll(option_space));
357}
358
359size_t
360CfgOption::del(const std::string& option_space, const uint16_t option_code) {
361 // Check for presence of options.
362 OptionContainerPtr options = getAll(option_space);
363 if (!options || options->empty()) {
364 // There are no options, so there is nothing to do.
365 return (0);
366 }
367
368 // If this is not top level option we may also need to delete the
369 // option instance from options encapsulating the particular option
370 // space.
371 if ((option_space != DHCP4_OPTION_SPACE) &&
372 (option_space != DHCP6_OPTION_SPACE)) {
373 // For each option space name iterate over the existing options.
374 auto option_space_names = getOptionSpaceNames();
375 for (auto const& option_space_from_list : option_space_names) {
376 // Get all options within the particular option space.
377 auto const& options_in_space = getAll(option_space_from_list);
378 for (auto const& option_it : *options_in_space) {
379
380 // Check if the option encapsulates our option space and
381 // it does, try to delete our option.
382 if (option_it.option_ &&
383 (option_it.option_->getEncapsulatedSpace() == option_space)) {
384 option_it.option_->delOption(option_code);
385 }
386 }
387 }
388 }
389
390 auto& idx = options->get<1>();
391 return (idx.erase(option_code));
392}
393
394size_t
395CfgOption::del(const uint32_t vendor_id, const uint16_t option_code) {
396 // Check for presence of options.
397 OptionContainerPtr vendor_options = getAll(vendor_id);
398 if (!vendor_options || vendor_options->empty()) {
399 // There are no options, so there is nothing to do.
400 return (0);
401 }
402
403 auto& idx = vendor_options->get<1>();
404 return (idx.erase(option_code));
405}
406
407size_t
408CfgOption::del(const uint64_t id) {
409 // Hierarchical nature of the options configuration requires that
410 // we go over all options and decapsulate them before removing
411 // any of them. Let's walk over the existing option spaces.
412 for (auto const& space_name : getOptionSpaceNames()) {
413 // Get all options for the option space.
414 auto const& options = getAll(space_name);
415 for (auto const& option_it : *options) {
416 if (!option_it.option_) {
417 continue;
418 }
419
420 // For each option within the option space we need to dereference
421 // any existing sub options.
422 auto sub_options = option_it.option_->getOptions();
423 for (auto const& sub : sub_options) {
424 // Dereference sub option.
425 option_it.option_->delOption(sub.second->getType());
426 }
427 }
428 }
429
430 // Now that we got rid of dependencies between the instances of the options
431 // we can delete all options having a specified id.
432 size_t num_deleted = options_.deleteItems(id) + vendor_options_.deleteItems(id);
433
434 // Let's encapsulate those options that remain in the configuration.
435 encapsulate();
436
437 // Return the number of deleted options.
438 return (num_deleted);
439}
440
443 return (toElementWithMetadata(false));
444}
445
447CfgOption::toElementWithMetadata(const bool include_metadata) const {
448 // option-data value is a list of maps
450 // Iterate first on options using space names
451 const std::list<std::string>& names = options_.getOptionSpaceNames();
452 for (auto const& name : names) {
453 OptionContainerPtr opts = getAll(name);
454 for (auto const& opt : *opts) {
455 // Get and fill the map for this option
457 // Set user context
458 opt.contextToElement(map);
459 // Set space from parent iterator
460 map->set("space", Element::create(name));
461 // Set the code
462 uint16_t code = opt.option_->getType();
463 map->set("code", Element::create(code));
464 // Set the name (always for standard options else when asked for)
466 if (!def) {
467 def = LibDHCP::getRuntimeOptionDef(name, code);
468 }
469 if (!def) {
470 def = LibDHCP::getLastResortOptionDef(name, code);
471 }
472 if (def) {
473 map->set("name", Element::create(def->getName()));
474 }
475 // Set the data item
476 if (!opt.formatted_value_.empty()) {
477 map->set("csv-format", Element::create(true));
478 if (def && def->getType() == OPT_EMPTY_TYPE) {
479 map->set("data", Element::create(""));
480 } else {
481 map->set("data", Element::create(opt.formatted_value_));
482 }
483 } else {
484 std::vector<uint8_t> bin = opt.option_->toBinary();
485 if (!opt.cancelled_ || !bin.empty()) {
486 map->set("csv-format", Element::create(false));
487 if (def && def->getType() == OPT_EMPTY_TYPE) {
488 map->set("data", Element::create(""));
489 } else {
490 std::string repr = util::encode::encodeHex(bin);
491 map->set("data", Element::create(repr));
492 }
493 }
494 }
495 // Set the persistency flag
496 map->set("always-send", Element::create(opt.persistent_));
497 // Set the cancelled flag.
498 map->set("never-send", Element::create(opt.cancelled_));
499 // Include metadata if requested.
500 if (include_metadata) {
501 map->set("metadata", opt.getMetadata());
502 }
503
504 // Push on the list
505 result->add(map);
506 }
507 }
508 // Iterate first on vendor_options using vendor ids
509 const std::list<uint32_t>& ids = vendor_options_.getOptionSpaceNames();
510 for (auto const& id : ids) {
511 OptionContainerPtr opts = getAll(id);
512 for (auto const& opt : *opts) {
513 // Get and fill the map for this option
515 // Set user context
516 opt.contextToElement(map);
517 // Set space from parent iterator
518 std::ostringstream oss;
519 oss << "vendor-" << id;
520 map->set("space", Element::create(oss.str()));
521 // Set the code
522 uint16_t code = opt.option_->getType();
523 map->set("code", Element::create(code));
524 // Set the name
525 Option::Universe universe = opt.option_->getUniverse();
527 LibDHCP::getVendorOptionDef(universe, id, code);
528 if (!def) {
529 // vendor-XXX space is in oss
530 def = LibDHCP::getRuntimeOptionDef(oss.str(), code);
531 }
532 if (def) {
533 map->set("name", Element::create(def->getName()));
534 }
535 // Set the data item
536 if (!opt.formatted_value_.empty()) {
537 map->set("csv-format", Element::create(true));
538 if (def && def->getType() == OPT_EMPTY_TYPE) {
539 map->set("data", Element::create(""));
540 } else {
541 map->set("data", Element::create(opt.formatted_value_));
542 }
543 } else {
544 std::vector<uint8_t> bin = opt.option_->toBinary();
545 if (!opt.cancelled_ || !bin.empty()) {
546 map->set("csv-format", Element::create(false));
547 if (def && def->getType() == OPT_EMPTY_TYPE) {
548 map->set("data", Element::create(""));
549 } else {
550 std::string repr = util::encode::encodeHex(bin);
551 map->set("data", Element::create(repr));
552 }
553 }
554 }
555 // Set the persistency flag
556 map->set("always-send", Element::create(opt.persistent_));
557 // Set the cancellation flag
558 map->set("never-send", Element::create(opt.cancelled_));
559 // Push on the list
560 result->add(map);
561 }
562 }
563 return (result);
564}
565
566} // namespace dhcp
567} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
void setId(const uint64_t id)
Sets element's database identifier.
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 data configuration for the DHCP server.
Definition: cfg_option.h:352
OptionContainerPtr getAllCombined(const std::string &option_space) const
Returns all non-vendor or vendor options for the specified option space.
Definition: cfg_option.cc:351
void encapsulate()
Appends encapsulated options to top-level options.
Definition: cfg_option.cc:262
void replace(const OptionDescriptor &desc, const std::string &option_space)
Replaces the instance of an option within this collection.
Definition: cfg_option.cc:101
static bool createDescriptorOption(CfgOptionDefPtr cfg_def, const std::string &space, OptionDescriptor &opt_desc)
Creates an option descriptor's option based on a set of option defs.
Definition: cfg_option.cc:176
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
Definition: cfg_option.cc:442
void createOptions(CfgOptionDefPtr cfg_def)
Re-create the option in each descriptor based on given definitions.
Definition: cfg_option.cc:161
isc::data::ElementPtr toElementWithMetadata(const bool include_metadata) const
Unparse a configuration object with optionally including the metadata.
Definition: cfg_option.cc:447
size_t del(const std::string &option_space, const uint16_t option_code)
Deletes option for the specified option space and option code.
Definition: cfg_option.cc:360
std::list< std::string > getOptionSpaceNames() const
Returns a list of configured option space names.
Definition: cfg_option.h:707
bool empty() const
Indicates the object is empty.
Definition: cfg_option.cc:59
void mergeTo(CfgOption &other) const
Merges this configuration to another configuration.
Definition: cfg_option.cc:246
void copyTo(CfgOption &other) const
Copies this configuration to another configuration.
Definition: cfg_option.cc:254
CfgOption()
default constructor
Definition: cfg_option.cc:54
std::list< std::string > getVendorIdsSpaceNames() const
Returns a list of option space names for configured vendor ids.
Definition: cfg_option.cc:126
OptionContainerPtr getAll(const std::string &option_space) const
Returns all options for the specified option space.
Definition: cfg_option.cc:341
void merge(CfgOptionDefPtr cfg_def, CfgOption &other)
Merges another option configuration into this one.
Definition: cfg_option.cc:140
bool equals(const CfgOption &other) const
Check if configuration is equal to other configuration.
Definition: cfg_option.cc:64
void add(const OptionPtr &option, const bool persistent, const bool cancelled, const std::string &option_space, const uint64_t id=0)
Adds instance of the option to the configuration.
Definition: cfg_option.cc:70
std::list< uint32_t > getVendorIds() const
Returns a list of all configured vendor identifiers.
Definition: cfg_option.h:712
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition: libdhcp++.cc:126
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:168
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
Definition: libdhcp++.cc:1298
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:189
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Definition: libdhcp++.cc:247
Option descriptor.
Definition: cfg_option.h:47
OptionPtr option_
Option instance.
Definition: cfg_option.h:50
std::string space_name_
Option space name.
Definition: cfg_option.h:90
bool equals(const OptionDescriptor &other) const
Checks if the one descriptor is equal to another.
Definition: cfg_option.cc:46
bool cancelled_
Cancelled flag.
Definition: cfg_option.h:64
std::string formatted_value_
Option value in textual (CSV) format.
Definition: cfg_option.h:79
static OptionDescriptorPtr create(const OptionPtr &opt, bool persist, bool cancel, const std::string &formatted_value="", data::ConstElementPtr user_context=data::ConstElementPtr())
Factory function creating an instance of the OptionDescriptor.
Definition: cfg_option.cc:27
bool persistent_
Persistence flag.
Definition: cfg_option.h:56
uint64_t deleteItems(const uint64_t id)
Remove all options or option definitions with a given database identifier.
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:83
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:29
boost::shared_ptr< Element > ElementPtr
Definition: data.h:28
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:310
OptionContainer::nth_index< 1 >::type OptionContainerTypeIndex
Type of the index #1 - option type.
Definition: cfg_option.h:305
boost::shared_ptr< CfgOptionDef > CfgOptionDefPtr
Non-const pointer.
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
boost::shared_ptr< OptionDescriptor > OptionDescriptorPtr
A pointer to option descriptor.
Definition: cfg_option.h:36
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
Definition: cfg_option.h:303
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_ > >, boost::multi_index::ordered_non_unique< boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > >, boost::multi_index::hashed_non_unique< boost::multi_index::tag< OptionIdIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, uint64_t, &data::BaseStampedElement::getId > >, boost::multi_index::hashed_non_unique< boost::multi_index::member< OptionDescriptor, bool, &OptionDescriptor::cancelled_ > > > > OptionContainer
Multi index container for DHCP option descriptors.
Definition: cfg_option.h:300
boost::shared_ptr< Option > OptionPtr
Definition: option.h:37
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 format.
Definition: encode.cc:361
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE