]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[github24] Support additional levels of option encapsulations.
authorMarcin Siodelski <marcin@isc.org>
Tue, 20 Sep 2016 11:00:35 +0000 (13:00 +0200)
committerMarcin Siodelski <marcin@isc.org>
Tue, 20 Sep 2016 12:31:24 +0000 (14:31 +0200)
src/lib/dhcpsrv/cfg_option.cc
src/lib/dhcpsrv/cfg_option.h
src/lib/dhcpsrv/tests/cfg_option_unittest.cc

index b901d6030d0eb5a4b2ab47069c3aec405e38f078..8947dd5335d3e063130cddab64cd62ce7a43f15a 100644 (file)
@@ -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_);
             }
         }
     }
index 065316fa6a59489e3766dd234e0e080b2f6d8095..61f3f13318508ca3d17428671b4ef318364a8610 100644 (file)
@@ -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
index 885b1ba401d1dc0b9489ba1a87dbf91086b3d2a4..3bcea0aa9357e8e490a93ef6cd668dc14e20db44 100644 (file)
@@ -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<unsigned int, OptionPtr> 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