From: Marcin Siodelski Date: Tue, 20 Sep 2016 11:00:35 +0000 (+0200) Subject: [github24] Support additional levels of option encapsulations. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bed30dc79516ff372200b44e619febe03f24e5bd;p=thirdparty%2Fkea.git [github24] Support additional levels of option encapsulations. --- diff --git a/src/lib/dhcpsrv/cfg_option.cc b/src/lib/dhcpsrv/cfg_option.cc index b901d6030d..8947dd5335 100644 --- a/src/lib/dhcpsrv/cfg_option.cc +++ b/src/lib/dhcpsrv/cfg_option.cc @@ -105,19 +105,31 @@ CfgOption::encapsulateInternal(const std::string& option_space) { // from the option spaces they encapsulate. for (OptionContainer::const_iterator opt = options->begin(); opt != options->end(); ++opt) { - // Get encapsulated option space for the option. - const std::string& encap_space = opt->option_->getEncapsulatedSpace(); - // Empty value means that no option space is encapsulated. - if (!encap_space.empty()) { - // Retrieve all options from the encapsulated option space. - OptionContainerPtr encap_options = getAll(encap_space); - for (OptionContainer::const_iterator encap_opt = - encap_options->begin(); encap_opt != encap_options->end(); - ++encap_opt) { - // Add sub-option if there isn't one added already. - if (!opt->option_->getOption(encap_opt->option_->getType())) { - opt->option_->addOption(encap_opt->option_); - } + encapsulateInternal(opt->option_); + } +} + +void +CfgOption::encapsulateInternal(const OptionPtr& option) { + // Get encapsulated option space for the option. + const std::string& encap_space = option->getEncapsulatedSpace(); + // Empty value means that no option space is encapsulated. + if (!encap_space.empty()) { + // Retrieve all options from the encapsulated option space. + OptionContainerPtr encap_options = getAll(encap_space); + for (OptionContainer::const_iterator encap_opt = + encap_options->begin(); encap_opt != encap_options->end(); + ++encap_opt) { + // Add sub-option if there isn't one added already. + if (!option->getOption(encap_opt->option_->getType())) { + option->addOption(encap_opt->option_); + } + // This is a workaround for preventing infinite recursion when + // trying to encapsulate options created with default global option + // spaces. + if (encap_space != DHCP4_OPTION_SPACE && + encap_space != DHCP6_OPTION_SPACE) { + encapsulateInternal(encap_opt->option_); } } } diff --git a/src/lib/dhcpsrv/cfg_option.h b/src/lib/dhcpsrv/cfg_option.h index 065316fa6a..61f3f13318 100644 --- a/src/lib/dhcpsrv/cfg_option.h +++ b/src/lib/dhcpsrv/cfg_option.h @@ -409,6 +409,16 @@ private: /// which encapsulated options are appended. void encapsulateInternal(const std::string& option_space); + /// @brief Appends encapsulated options from the option space encapsulated + /// by the specified option. + /// + /// This method will go over all options belonging to the encapsulated space + /// and will check which option spaces they encapsulate recursively, + /// adding these options to the current option + /// + /// @param option which encapsulated options. + void encapsulateInternal(const OptionPtr& option); + /// @brief Merges data from two option containers. /// /// This method merges options from one option container to another diff --git a/src/lib/dhcpsrv/tests/cfg_option_unittest.cc b/src/lib/dhcpsrv/tests/cfg_option_unittest.cc index 885b1ba401..3bcea0aa93 100644 --- a/src/lib/dhcpsrv/tests/cfg_option_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_option_unittest.cc @@ -307,7 +307,7 @@ TEST(CfgOptionTest, encapsulate) { } // Create sub-options belonging to "bar-subs" option space. - for (uint16_t code = 500; code < 510; ++code) { + for (uint16_t code = 501; code < 510; ++code) { OptionUint8Ptr option = OptionUint8Ptr(new OptionUint8(Option::V6, code, 0x04)); ASSERT_NO_THROW(cfg.add(option, false, "bar-subs")); @@ -352,17 +352,18 @@ TEST(CfgOptionTest, encapsulate) { EXPECT_EQ(2, value); } - // Each first level sub-option should include 10 second level + // Each first level sub-option should include 9 second level // sub options. const OptionCollection& second_level = first_level_uint8->getOptions(); - ASSERT_EQ(10, second_level.size()); + ASSERT_EQ(9, second_level.size()); // Iterate over sub-options and make sure they include the expected // values. std::pair second_level_opt; BOOST_FOREACH(second_level_opt, second_level) { OptionUint8Ptr second_level_uint8 = boost::dynamic_pointer_cast< - OptionUint8>(second_level_uint8); + OptionUint8>(second_level_opt.second); + ASSERT_TRUE(second_level_uint8); const unsigned value = static_cast< unsigned>(second_level_uint8->getValue()); // Certain sub-options should have a value of 3, other the values