Browse Source

[4204] Runtime option definitions are stored in LibDHCP.

Marcin Siodelski 9 years ago
parent
commit
1e7bdebfd5
3 changed files with 157 additions and 1 deletions
  1. 48 1
      src/lib/dhcp/libdhcp++.cc
  2. 31 0
      src/lib/dhcp/libdhcp++.h
  3. 78 0
      src/lib/dhcp/tests/libdhcp++_unittest.cc

+ 48 - 1
src/lib/dhcp/libdhcp++.cc

@@ -32,6 +32,8 @@
 #include <boost/shared_array.hpp>
 #include <boost/shared_ptr.hpp>
 
+#include <list>
+
 using namespace std;
 using namespace isc::dhcp;
 using namespace isc::util;
@@ -198,9 +200,47 @@ LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
     return (OptionDefinitionPtr());
 }
 
+OptionDefinitionPtr
+LibDHCP::getRuntimeOptionDef(const std::string& space, const uint16_t code) {
+    OptionDefContainerPtr container = runtime_option_defs_.getItems(space);
+    const OptionDefContainerTypeIndex& index = container->get<1>();
+    const OptionDefContainerTypeRange& range = index.equal_range(code);
+    if (range.first != range.second) {
+        return (*range.first);
+    }
+
+    return (OptionDefinitionPtr());
+}
+
+OptionDefinitionPtr
+LibDHCP::getRuntimeOptionDef(const std::string& space, const std::string& name) {
+    OptionDefContainerPtr container = runtime_option_defs_.getItems(space);
+    const OptionDefContainerNameIndex& index = container->get<2>();
+    const OptionDefContainerNameRange& range = index.equal_range(name);
+    if (range.first != range.second) {
+        return (*range.first);
+    }
+
+    return (OptionDefinitionPtr());
+}
+
+OptionDefContainerPtr
+LibDHCP::getRuntimeOptionDefs(const std::string& space) {
+    return (runtime_option_defs_.getItems(space));
+}
+
 void
 LibDHCP::setRuntimeOptionDefs(const OptionDefSpaceContainer& defs) {
-    
+    std::list<std::string> option_space_names = defs.getOptionSpaceNames();
+    for (std::list<std::string>::const_iterator name = option_space_names.begin();
+         name != option_space_names.end(); ++name) {
+        OptionDefContainerPtr container = defs.getItems(*name);
+        for (OptionDefContainer::const_iterator def = container->begin();
+             def != container->end(); ++def) {
+            OptionDefinitionPtr def_copy(new OptionDefinition(**def));
+            runtime_option_defs_.addItem(def_copy, *name);
+        }
+    }
 }
 
 void
@@ -275,7 +315,14 @@ size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
     OptionDefContainer option_defs;
     if (option_space == "dhcp6") {
         option_defs = LibDHCP::getOptionDefs(Option::V6);
+    } else {
+        OptionDefContainerPtr option_defs_ptr =
+            LibDHCP::getRuntimeOptionDefs(option_space);
+        if (option_defs_ptr) {
+            option_defs = *option_defs_ptr;
+        }
     }
+
     // @todo Once we implement other option spaces we should add else clause
     // here and gather option definitions for them. For now leaving option_defs
     // empty will imply creation of generic Option.

+ 31 - 0
src/lib/dhcp/libdhcp++.h

@@ -91,6 +91,37 @@ public:
                                                   const uint32_t vendor_id,
                                                   const std::string& name);
 
+
+    /// @brief Returns runtime (non-standard) option definition by space and
+    /// option code.
+    ///
+    /// @param space Option space name.
+    /// @param code Option code.
+    ///
+    /// @return Pointer to option definition or NULL if it doesn't exist.
+    static OptionDefinitionPtr getRuntimeOptionDef(const std::string& space,
+                                                   const uint16_t code);
+
+    /// @brief Returns runtime (non-standard) option definition by space and
+    /// option name.
+    ///
+    /// @param space Option space name.
+    /// @param name Option name.
+    ///
+    /// @return Pointer to option definition or NULL if it doesn't exist.
+    static OptionDefinitionPtr getRuntimeOptionDef(const std::string& space,
+                                                   const std::string& name);
+
+    /// @brief Returns runtime (non-standard) option definitions for specified
+    /// option space name.
+    ///
+    /// @param space Option space name.
+    ///
+    /// @return Pointer to the container holding option definitions or NULL.
+    static OptionDefContainerPtr
+    getRuntimeOptionDefs(const std::string& space);
+
+
     /// @brief Check if the specified option is a standard option.
     ///
     /// @param u universe (V4 or V6)

+ 78 - 0
src/lib/dhcp/tests/libdhcp++_unittest.cc

@@ -147,6 +147,60 @@ public:
         return (OptionBuffer(opt_data, opt_data + sizeof(opt_data)));
     }
 
+    /// @brief Create option definitions and store in the container.
+    ///
+    /// @param spaces_num Number of option spaces to be created.
+    /// @param defs_num Number of option definitions to be created for
+    /// each option space.
+    /// @param [out] defs Container to which option definitions should be
+    /// added.
+    static void createRuntimeOptionDefs(const uint16_t spaces_num,
+                                        const uint16_t defs_num,
+                                        OptionDefSpaceContainer& defs) {
+        for (uint16_t space = 0; space < spaces_num; ++space) {
+            std::ostringstream space_name;
+            space_name << "option-space-" << space;
+            for (uint16_t code = 0; code < defs_num; ++code) {
+                std::ostringstream name;
+                name << "name-for-option-" << code;
+                OptionDefinitionPtr opt_def(new OptionDefinition(name.str(),
+                                                                 code, "string"));
+                defs.addItem(opt_def, space_name.str());
+            }
+        }
+    }
+
+    /// @brief Test if runtime option definitions have been added.
+    ///
+    /// This method uses the same naming conventions for space names and
+    /// options names as @c createRuntimeOptionDefs method.
+    ///
+    /// @param spaces_num Number of option spaces to be tested.
+    /// @param defs_num Number of option definitions that should exist
+    /// in each option space.
+    /// @param should_exist Boolean value which indicates if option
+    /// definitions should exist. If this is false, this function will
+    /// check that they don't exist.
+    static void testRuntimeOptionDefs(const uint16_t spaces_num,
+                                      const uint16_t defs_num,
+                                      const bool should_exist) {
+        for (uint16_t space = 0; space < spaces_num; ++space) {
+            std::ostringstream space_name;
+            space_name << "option-space-" << space;
+            for (uint16_t code = 0; code < defs_num; ++code) {
+                std::ostringstream name;
+                name << "name-for-option-" << code;
+                OptionDefinitionPtr opt_def =
+                    LibDHCP::getRuntimeOptionDef(space_name.str(), name.str());
+                if (should_exist) {
+                    ASSERT_TRUE(opt_def);
+                } else {
+                    ASSERT_FALSE(opt_def);
+                }
+            }
+        }
+    }
+
 private:
 
     /// @brief Test DHCPv4 or DHCPv6 option definition.
@@ -1319,4 +1373,28 @@ TEST_F(LibDhcpTest, vendorClass6) {
     EXPECT_EQ("eRouter1.0", vclass->getTuple(0).getText());
 }
 
+// This test verifies that it is possible to add runtime option definitions,
+// retrieve them and remove them.
+TEST_F(LibDhcpTest, setRuntimeOptionDefs) {
+    // Create option definitions in 5 namespaces.
+    OptionDefSpaceContainer defs;
+    createRuntimeOptionDefs(5, 100, defs);
+
+    // Apply option definitions.
+    ASSERT_NO_THROW(LibDHCP::setRuntimeOptionDefs(defs));
+
+    // Retrieve all inserted option definitions.
+    testRuntimeOptionDefs(5, 100, true);
+
+    // Attempting to retrieve non existing definitions.
+    EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("option-space-non-existent", 1));
+    EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("option-space-0", 145));
+
+    // Remove all runtime option definitions.
+    ASSERT_NO_THROW(LibDHCP::clearRuntimeOptionDefs());
+
+    // All option definitions should be gone now.
+    testRuntimeOptionDefs(5, 100, false);
+}
+
 } // end of anonymous space