cfg_option.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright (C) 2014-2016 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. #include <dhcp/libdhcp++.h>
  7. #include <dhcp/option_space.h>
  8. #include <dhcpsrv/cfg_option.h>
  9. #include <dhcp/dhcp6.h>
  10. #include <string>
  11. namespace isc {
  12. namespace dhcp {
  13. bool
  14. OptionDescriptor::equals(const OptionDescriptor& other) const {
  15. return (persistent_ == other.persistent_ &&
  16. formatted_value_ == other.formatted_value_ &&
  17. option_->equals(other.option_));
  18. }
  19. CfgOption::CfgOption() {
  20. }
  21. bool
  22. CfgOption::empty() const {
  23. return (options_.empty() && vendor_options_.empty());
  24. }
  25. bool
  26. CfgOption::equals(const CfgOption& other) const {
  27. return (options_.equals(other.options_) &&
  28. vendor_options_.equals(other.vendor_options_));
  29. }
  30. void
  31. CfgOption::add(const OptionPtr& option, const bool persistent,
  32. const std::string& option_space) {
  33. add(OptionDescriptor(option, persistent), option_space);
  34. }
  35. void
  36. CfgOption::add(const OptionDescriptor& desc, const std::string& option_space) {
  37. if (!desc.option_) {
  38. isc_throw(isc::BadValue, "option being configured must not be NULL");
  39. } else if (!OptionSpace::validateName(option_space)) {
  40. isc_throw(isc::BadValue, "invalid option space name: '"
  41. << option_space << "'");
  42. }
  43. const uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(option_space);
  44. if (vendor_id) {
  45. vendor_options_.addItem(desc, vendor_id);
  46. } else {
  47. options_.addItem(desc, option_space);
  48. }
  49. }
  50. std::list<std::string>
  51. CfgOption::getVendorIdsSpaceNames() const {
  52. std::list<uint32_t> ids = getVendorIds();
  53. std::list<std::string> names;
  54. for (std::list<uint32_t>::const_iterator id = ids.begin();
  55. id != ids.end(); ++id) {
  56. std::ostringstream s;
  57. // Vendor space name is constructed as "vendor-XYZ" where XYZ is an
  58. // uint32_t value, without leading zeros.
  59. s << "vendor-" << *id;
  60. names.push_back(s.str());
  61. }
  62. return (names);
  63. }
  64. void
  65. CfgOption::mergeTo(CfgOption& other) const {
  66. // Merge non-vendor options.
  67. mergeInternal(options_, other.options_);
  68. // Merge vendor options.
  69. mergeInternal(vendor_options_, other.vendor_options_);
  70. }
  71. void
  72. CfgOption::copyTo(CfgOption& other) const {
  73. // Remove any existing data in the destination.
  74. other.options_.clearItems();
  75. other.vendor_options_.clearItems();
  76. mergeTo(other);
  77. }
  78. void
  79. CfgOption::encapsulate() {
  80. // Append sub-options to the top level "dhcp4" option space.
  81. encapsulateInternal(DHCP4_OPTION_SPACE);
  82. // Append sub-options to the top level "dhcp6" option space.
  83. encapsulateInternal(DHCP6_OPTION_SPACE);
  84. }
  85. void
  86. CfgOption::encapsulateInternal(const std::string& option_space) {
  87. // Get all options for the particular option space.
  88. OptionContainerPtr options = getAll(option_space);
  89. // For each option in the option space we will append sub-options
  90. // from the option spaces they encapsulate.
  91. for (OptionContainer::const_iterator opt = options->begin();
  92. opt != options->end(); ++opt) {
  93. // Get encapsulated option space for the option.
  94. const std::string& encap_space = opt->option_->getEncapsulatedSpace();
  95. // Empty value means that no option space is encapsulated.
  96. if (!encap_space.empty()) {
  97. // Retrieve all options from the encapsulated option space.
  98. OptionContainerPtr encap_options = getAll(encap_space);
  99. for (OptionContainer::const_iterator encap_opt =
  100. encap_options->begin(); encap_opt != encap_options->end();
  101. ++encap_opt) {
  102. // Add sub-option if there isn't one added already.
  103. if (!opt->option_->getOption(encap_opt->option_->getType())) {
  104. opt->option_->addOption(encap_opt->option_);
  105. }
  106. }
  107. }
  108. }
  109. }
  110. template <typename Selector>
  111. void
  112. CfgOption::mergeInternal(const OptionSpaceContainer<OptionContainer,
  113. OptionDescriptor, Selector>& src_container,
  114. OptionSpaceContainer<OptionContainer,
  115. OptionDescriptor, Selector>& dest_container) const {
  116. // Get all option spaces used in source container.
  117. std::list<Selector> selectors = src_container.getOptionSpaceNames();
  118. // For each space in the source container retrieve the actual options and
  119. // match them with the options held in the destination container under
  120. // the same space.
  121. for (typename std::list<Selector>::const_iterator it = selectors.begin();
  122. it != selectors.end(); ++it) {
  123. // Get all options in the destination container for the particular
  124. // option space.
  125. OptionContainerPtr dest_all = dest_container.getItems(*it);
  126. OptionContainerPtr src_all = src_container.getItems(*it);
  127. // For each option under this option space check if there is a
  128. // corresponding option in the destination container. If not,
  129. // add one.
  130. for (OptionContainer::const_iterator src_opt = src_all->begin();
  131. src_opt != src_all->end(); ++src_opt) {
  132. const OptionContainerTypeIndex& idx = dest_all->get<1>();
  133. const OptionContainerTypeRange& range =
  134. idx.equal_range(src_opt->option_->getType());
  135. // If there is no such option in the destination container,
  136. // add one.
  137. if (std::distance(range.first, range.second) == 0) {
  138. dest_container.addItem(OptionDescriptor(src_opt->option_,
  139. src_opt->persistent_),
  140. *it);
  141. }
  142. }
  143. }
  144. }
  145. OptionContainerPtr
  146. CfgOption::getAll(const std::string& option_space) const {
  147. return (options_.getItems(option_space));
  148. }
  149. OptionContainerPtr
  150. CfgOption::getAll(const uint32_t vendor_id) const {
  151. return (vendor_options_.getItems(vendor_id));
  152. }
  153. } // end of namespace isc::dhcp
  154. } // end of namespace isc