Parcourir la source

[2981] Added storage of hooks library names to the DHCP config manager

Stephen Morris il y a 11 ans
Parent
commit
ed363b3698
3 fichiers modifiés avec 106 ajouts et 5 suppressions
  1. 18 0
      src/lib/dhcpsrv/cfgmgr.cc
  2. 55 5
      src/lib/dhcpsrv/cfgmgr.h
  3. 33 0
      src/lib/dhcpsrv/tests/cfgmgr_unittest.cc

+ 18 - 0
src/lib/dhcpsrv/cfgmgr.cc

@@ -266,6 +266,24 @@ std::string CfgMgr::getDataDir() {
     return (datadir_);
 }
 
+void
+CfgMgr::setHooksLibraries(const std::vector<std::string>& hooks_libraries) {
+    hooks_libraries_.reset(new std::vector<std::string>(hooks_libraries));
+}
+
+boost::shared_ptr<std::vector<std::string> >
+CfgMgr::getAndClearHooksLibraries() {
+    // Create shared pointer pointing to nothing.
+    boost::shared_ptr<std::vector<std::string> > libraries;
+
+    // Set the new variable to point to the stored hooks libraries and clear
+    // the stored value.
+    libraries.swap(hooks_libraries_);
+
+    return (libraries);
+}
+
+
 
 CfgMgr::CfgMgr()
     :datadir_(DHCP_DATA_DIR) {

+ 55 - 5
src/lib/dhcpsrv/cfgmgr.h

@@ -38,10 +38,19 @@ namespace dhcp {
 /// @brief Configuration Manager
 ///
 /// This singleton class holds the whole configuration for DHCPv4 and DHCPv6
-/// servers. It currently holds information about zero or more subnets6.
-/// Each subnet may contain zero or more pools. Pool4 and Pool6 is the most
-/// basic "chunk" of configuration. It contains a range of assignable
-/// addresses.
+/// servers. It currently holds information about:
+/// - Zero or more subnets.  Each subnet may contain zero or more pools. Pool4
+///   and Pool6 is the most basic "chunk" of configuration. It contains a range
+///   of assignable addresses.
+/// - Hook libraries. Hooks library names are stored here, but only up to the
+///   point that the libraries are reloaded.  In more detail: libraries
+///   containing hooks callouts can only be loaded and reloaded safely (or, more
+///   accurately, unloaded safely) when no data structure in the server contains
+///   a reference to any memory allocated by a function in them.  In practice
+///   this means when there are no packets being activly processed.  Rather than
+///   take a chance that the configuration code will do the unload/load at the
+///   right time, the configuration code sets the names of the new libraries in
+///   this object and the server decides when to reconfigure the hooks.
 ///
 /// Below is a sketch of configuration inheritance (not implemented yet).
 /// Let's investigate the following configuration:
@@ -68,6 +77,7 @@ namespace dhcp {
 /// routines, so there is no storage capability in a global scope for
 /// subnet-specific parameters.
 ///
+/// ARE THESE DONE?
 /// @todo: Implement Subnet4 support (ticket #2237)
 /// @todo: Implement option definition support
 /// @todo: Implement parameter inheritance
@@ -229,7 +239,6 @@ public:
     /// completely new?
     void deleteSubnets4();
 
-
     /// @brief returns path do the data directory
     ///
     /// This method returns a path to writeable directory that DHCP servers
@@ -237,6 +246,25 @@ public:
     /// @return data directory
     std::string getDataDir();
 
+    /// @brief Sets list of hooks libraries
+    ///
+    /// Sets the list of hooks libraries.  It is possible for there to be no
+    /// hooks libraries, in which case this is indicated by an emopty vector.
+    ///
+    /// @param hooks_libraries Vector (possibly empty) of current hook libraries.
+    void setHooksLibraries(const std::vector<std::string>& hooks_libraries);
+
+    /// @brief Get and clear list of hooks libraries
+    ///
+    /// Gets the currently-set vector of hooks libraries.  If there is no data
+    /// (as opposed to an empty vector), there has been no change to the data
+    /// since the last time this method was called. Should there be a necessity
+    /// to know this information, it can be obtained from the HooksManager.
+    ///
+    /// @return Pointer to vector of strings listing the hooks libraries.  This
+    ///         may be empty.
+    boost::shared_ptr<std::vector<std::string> > getAndClearHooksLibraries();
+
 protected:
 
     /// @brief Protected constructor.
@@ -283,6 +311,28 @@ private:
 
     /// @brief directory where data files (e.g. server-id) are stored
     std::string datadir_;
+
+    /// @brief Hooks libraries
+    ///
+    /// Unlike other configuration items that can be referenced all the time,
+    /// this is a "one-shot" item.  When the list of libraries is altered, the
+    /// server needs to know about the change: once the libraries are loaded,
+    /// the list is ignored.  As configuration updates cause an update of the
+    /// entire configuration and we wish to reload the libraries only if the
+    /// list has changed, we could check the library list against that stored
+    /// in the hooks manager.  Unfortunately, since the libraries are reloaded
+    /// when a new packet is received, this would mean a set of string
+    /// comparisons on each packet.  Instead, the data is flagged to indicate
+    /// that it has changed.
+    ///
+    /// The parsing checks the set of hooks libraries in the configuration
+    /// against the list stored in the HooksManager and only updates the data
+    /// here if they have changed.  Although a flag could be used to indicate
+    /// a change, a more streamlined approach is used: the data in this object
+    /// is cleared when it is read.  As the data is a vector of strings and as
+    /// an empty vector is valid data, we'll store the data as a shared pointer
+    /// to a vector of strings.  The pointer is zeroed when the data is read.
+    boost::shared_ptr<std::vector<std::string> > hooks_libraries_;
 };
 
 } // namespace isc::dhcp

+ 33 - 0
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc

@@ -165,6 +165,7 @@ public:
         CfgMgr::instance().deleteSubnets4();
         CfgMgr::instance().deleteSubnets6();
         CfgMgr::instance().deleteOptionDefs();
+        static_cast<void>(CfgMgr::instance().getAndClearHooksLibraries());
     }
 
     /// @brief generates interface-id option based on provided text
@@ -182,6 +183,7 @@ public:
         CfgMgr::instance().deleteSubnets4();
         CfgMgr::instance().deleteSubnets6();
         CfgMgr::instance().deleteOptionDefs();
+        static_cast<void>(CfgMgr::instance().getAndClearHooksLibraries());
     }
 };
 
@@ -577,4 +579,35 @@ TEST_F(CfgMgrTest, optionSpace6) {
 // in Dhcpv6SrvTest.selectSubnetAddr and Dhcpv6SrvTest.selectSubnetIface
 // (see src/bin/dhcp6/tests/dhcp6_srv_unittest.cc)
 
+// Checks that the hooks libraries can be set correctly.
+TEST_F(CfgMgrTest, hooksLibraries) {
+    std::vector<std::string> test_libraries;
+    test_libraries.push_back("/usr/lib/alpha.so");
+    test_libraries.push_back("/usr/lib/beta.so");
+
+    std::vector<std::string> no_libraries;
+
+    // The pointer should be empty initially.
+    boost::shared_ptr<std::vector<std::string> > config_libraries =
+        CfgMgr::instance().getAndClearHooksLibraries();
+    EXPECT_FALSE(config_libraries);
+
+    // Set the new set of libraries and get them.
+    CfgMgr::instance().setHooksLibraries(test_libraries);
+    config_libraries = CfgMgr::instance().getAndClearHooksLibraries();
+    ASSERT_TRUE(config_libraries);
+    EXPECT_TRUE(test_libraries == *config_libraries);
+
+    // Expect the get operation to have cleared the stored libraries.
+    config_libraries = CfgMgr::instance().getAndClearHooksLibraries();
+    EXPECT_FALSE(config_libraries);
+
+    // Check that the methods also work with an empty library vector.
+    CfgMgr::instance().setHooksLibraries(no_libraries);
+    config_libraries = CfgMgr::instance().getAndClearHooksLibraries();
+    ASSERT_TRUE(config_libraries);
+    EXPECT_TRUE(config_libraries->empty());
+}
+
+
 } // end of anonymous namespace