Kea  2.5.3
cfg_option.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2023 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 <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 
21 using namespace isc::data;
22 
23 namespace isc {
24 namespace dhcp {
25 
27 OptionDescriptor::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 
36 OptionDescriptor::create(bool persist, bool cancel) {
37  return (boost::make_shared<OptionDescriptor>(persist, cancel));
38 }
39 
41 OptionDescriptor::create(const OptionDescriptor& desc) {
42  return (boost::make_shared<OptionDescriptor>(desc));
43 }
44 
45 bool
46 OptionDescriptor::equals(const OptionDescriptor& other) const {
47  return ((persistent_ == other.persistent_) &&
48  (cancelled_ == other.cancelled_) &&
49  (formatted_value_ == other.formatted_value_) &&
50  (space_name_ == other.space_name_) &&
51  option_->equals(other.option_));
52 }
53 
54 CfgOption::CfgOption()
55  : encapsulated_(false) {
56 }
57 
58 bool
60  return (options_.empty() && vendor_options_.empty());
61 }
62 
63 bool
64 CfgOption::equals(const CfgOption& other) const {
65  return (options_.equals(other.options_) &&
66  vendor_options_.equals(other.vendor_options_));
67 }
68 
69 void
70 CfgOption::add(const OptionPtr& option,
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 
82 void
83 CfgOption::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 
100 void
101 CfgOption::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 
125 std::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 
139 void
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 
160 void
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 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 
175 bool
176 CfgOption::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.
188  OptionDefinitionPtr def = LibDHCP::getOptionDef(space, code);
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 
245 void
247  // Merge non-vendor options.
248  mergeInternal(options_, other.options_);
249  // Merge vendor options.
250  mergeInternal(vendor_options_, other.vendor_options_);
251 }
252 
253 void
255  // Remove any existing data in the destination.
256  other.options_.clearItems();
257  other.vendor_options_.clearItems();
258  mergeTo(other);
259 }
260 
261 void
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 
270 void
271 CfgOption::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 
281 void
282 CfgOption::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 
307 template <typename Selector>
308 void
309 CfgOption::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 
341 CfgOption::getAll(const std::string& option_space) const {
342  return (options_.getItems(option_space));
343 }
344 
346 CfgOption::getAll(const uint32_t vendor_id) const {
347  return (vendor_options_.getItems(vendor_id));
348 }
349 
351 CfgOption::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 
359 size_t
360 CfgOption::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 option_space_from_list : option_space_names) {
376  // Get all options within the particular option space.
377  auto options_in_space = getAll(option_space_from_list);
378  for (auto option_it = options_in_space->begin();
379  option_it != options_in_space->end();
380  ++option_it) {
381 
382  // Check if the option encapsulates our option space and
383  // it does, try to delete our option.
384  if (option_it->option_ &&
385  (option_it->option_->getEncapsulatedSpace() == option_space)) {
386  option_it->option_->delOption(option_code);
387  }
388  }
389  }
390  }
391 
392  auto& idx = options->get<1>();
393  return (idx.erase(option_code));
394 }
395 
396 size_t
397 CfgOption::del(const uint32_t vendor_id, const uint16_t option_code) {
398  // Check for presence of options.
399  OptionContainerPtr vendor_options = getAll(vendor_id);
400  if (!vendor_options || vendor_options->empty()) {
401  // There are no options, so there is nothing to do.
402  return (0);
403  }
404 
405  auto& idx = vendor_options->get<1>();
406  return (idx.erase(option_code));
407 }
408 
409 size_t
410 CfgOption::del(const uint64_t id) {
411  // Hierarchical nature of the options configuration requires that
412  // we go over all options and decapsulate them before removing
413  // any of them. Let's walk over the existing option spaces.
414  for (auto space_name : getOptionSpaceNames()) {
415  // Get all options for the option space.
416  auto options = getAll(space_name);
417  for (auto option_it = options->begin(); option_it != options->end();
418  ++option_it) {
419  if (!option_it->option_) {
420  continue;
421  }
422 
423  // For each option within the option space we need to dereference
424  // any existing sub options.
425  auto sub_options = option_it->option_->getOptions();
426  for (auto sub = sub_options.begin(); sub != sub_options.end();
427  ++sub) {
428  // Dereference sub option.
429  option_it->option_->delOption(sub->second->getType());
430  }
431  }
432  }
433 
434  // Now that we got rid of dependencies between the instances of the options
435  // we can delete all options having a specified id.
436  size_t num_deleted = options_.deleteItems(id) + vendor_options_.deleteItems(id);
437 
438  // Let's encapsulate those options that remain in the configuration.
439  encapsulate();
440 
441  // Return the number of deleted options.
442  return (num_deleted);
443 }
444 
447  return (toElementWithMetadata(false));
448 }
449 
451 CfgOption::toElementWithMetadata(const bool include_metadata) const {
452  // option-data value is a list of maps
453  ElementPtr result = Element::createList();
454  // Iterate first on options using space names
455  const std::list<std::string>& names = options_.getOptionSpaceNames();
456  for (auto const& name : names) {
457  OptionContainerPtr opts = getAll(name);
458  for (auto const& opt : *opts) {
459  // Get and fill the map for this option
461  // Set user context
462  opt.contextToElement(map);
463  // Set space from parent iterator
464  map->set("space", Element::create(name));
465  // Set the code
466  uint16_t code = opt.option_->getType();
467  map->set("code", Element::create(code));
468  // Set the name (always for standard options else when asked for)
469  OptionDefinitionPtr def = LibDHCP::getOptionDef(name, code);
470  if (!def) {
471  def = LibDHCP::getRuntimeOptionDef(name, code);
472  }
473  if (!def) {
474  def = LibDHCP::getLastResortOptionDef(name, code);
475  }
476  if (def) {
477  map->set("name", Element::create(def->getName()));
478  }
479  // Set the data item
480  if (!opt.formatted_value_.empty()) {
481  map->set("csv-format", Element::create(true));
482  map->set("data", Element::create(opt.formatted_value_));
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  std::string repr = util::encode::encodeHex(bin);
488  map->set("data", Element::create(repr));
489  }
490  }
491  // Set the persistency flag
492  map->set("always-send", Element::create(opt.persistent_));
493  // Set the cancelled flag.
494  map->set("never-send", Element::create(opt.cancelled_));
495  // Include metadata if requested.
496  if (include_metadata) {
497  map->set("metadata", opt.getMetadata());
498  }
499 
500  // Push on the list
501  result->add(map);
502  }
503  }
504  // Iterate first on vendor_options using vendor ids
505  const std::list<uint32_t>& ids = vendor_options_.getOptionSpaceNames();
506  for (auto const& id : ids) {
507  OptionContainerPtr opts = getAll(id);
508  for (auto const& opt : *opts) {
509  // Get and fill the map for this option
511  // Set user context
512  opt.contextToElement(map);
513  // Set space from parent iterator
514  std::ostringstream oss;
515  oss << "vendor-" << id;
516  map->set("space", Element::create(oss.str()));
517  // Set the code
518  uint16_t code = opt.option_->getType();
519  map->set("code", Element::create(code));
520  // Set the name
521  Option::Universe universe = opt.option_->getUniverse();
522  OptionDefinitionPtr def =
523  LibDHCP::getVendorOptionDef(universe, id, code);
524  if (!def) {
525  // vendor-XXX space is in oss
526  def = LibDHCP::getRuntimeOptionDef(oss.str(), code);
527  }
528  if (def) {
529  map->set("name", Element::create(def->getName()));
530  }
531  // Set the data item
532  if (!opt.formatted_value_.empty()) {
533  map->set("csv-format", Element::create(true));
534  map->set("data", Element::create(opt.formatted_value_));
535  } else {
536  std::vector<uint8_t> bin = opt.option_->toBinary();
537  if (!opt.cancelled_ || !bin.empty()) {
538  map->set("csv-format", Element::create(false));
539  std::string repr = util::encode::encodeHex(bin);
540  map->set("data", Element::create(repr));
541  }
542  }
543  // Set the persistency flag
544  map->set("always-send", Element::create(opt.persistent_));
545  // Set the cancellation flag
546  map->set("never-send", Element::create(opt.cancelled_));
547  // Push on the list
548  result->add(map);
549  }
550  }
551  return (result);
552 }
553 
554 } // namespace dhcp
555 } // 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:246
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:301
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:296
Represents option data configuration for the DHCP server.
Definition: cfg_option.h:351
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:446
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:451
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
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
std::list< std::string > getOptionSpaceNames() const
Returns a list of configured option space names.
Definition: cfg_option.h:707
std::list< std::string > getVendorIdsSpaceNames() const
Returns a list of option space names for configured vendor ids.
Definition: cfg_option.cc:126
std::list< uint32_t > getVendorIds() const
Returns a list of all configured vendor identifiers.
Definition: cfg_option.h:712
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
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition: libdhcp++.cc:124
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:166
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
Definition: libdhcp++.cc:1296
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:187
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Definition: libdhcp++.cc:245
Option descriptor.
Definition: cfg_option.h:46
OptionPtr option_
Option instance.
Definition: cfg_option.h:49
std::string space_name_
Option space name.
Definition: cfg_option.h:89
bool cancelled_
Cancelled flag.
Definition: cfg_option.h:63
std::string formatted_value_
Option value in textual (CSV) format.
Definition: cfg_option.h:78
bool persistent_
Persistence flag.
Definition: cfg_option.h:55
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:26
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:309
OptionContainer::nth_index< 1 >::type OptionContainerTypeIndex
Type of the index #1 - option type.
Definition: cfg_option.h:304
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:32
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
Definition: cfg_option.h:302
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:299
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 ('hex') format.
Definition: base_n.cc:483
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE