Browse Source

[3971] DHCPv6 server uses TimerMgr to run LFC timers.

Marcin Siodelski 9 years ago
parent
commit
7e7ea2756a

+ 30 - 1
src/bin/dhcp6/ctrl_dhcp6_srv.cc

@@ -118,8 +118,34 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
         return (no_srv);
         return (no_srv);
     }
     }
 
 
+    // We're going to modify the timers configuration. This is not allowed
+    // when the thread is running.
+    try {
+        TimerMgr::instance()->stopThread();
+    } catch (const std::exception& ex) {
+        std::ostringstream err;
+        err << "Unable to stop worker thread running timers: "
+            << ex.what() << ".";
+        return (isc::config::createAnswer(1, err.str()));
+    }
+
     ConstElementPtr answer = configureDhcp6Server(*srv, config);
     ConstElementPtr answer = configureDhcp6Server(*srv, config);
 
 
+    // Start worker thread if there are any timers installed. Note that
+    // we also start worker thread when the reconfiguration failed, because
+    // in that case we continue using an old configuration and the server
+    // should still run installed timers.
+    if (TimerMgr::instance()->timersCount() > 0) {
+        try {
+            TimerMgr::instance()->startThread();
+        } catch (const std::exception& ex) {
+            std::ostringstream err;
+            err << "Unable to start worker thread running timers: "
+                << ex.what() << ".";
+            return (isc::config::createAnswer(1, err.str()));
+        }
+    }
+
     // Check that configuration was successful. If not, do not reopen sockets
     // Check that configuration was successful. If not, do not reopen sockets
     // and don't bother with DDNS stuff.
     // and don't bother with DDNS stuff.
     try {
     try {
@@ -156,7 +182,7 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
 }
 }
 
 
 ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port)
 ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port)
-    : Dhcpv6Srv(port) {
+    : Dhcpv6Srv(port), io_service_(), timer_mgr_(TimerMgr::instance()) {
     if (server_) {
     if (server_) {
         isc_throw(InvalidOperation,
         isc_throw(InvalidOperation,
                   "There is another Dhcpv6Srv instance already.");
                   "There is another Dhcpv6Srv instance already.");
@@ -198,6 +224,9 @@ void ControlledDhcpv6Srv::shutdown() {
 ControlledDhcpv6Srv::~ControlledDhcpv6Srv() {
 ControlledDhcpv6Srv::~ControlledDhcpv6Srv() {
     cleanup();
     cleanup();
 
 
+    // Stop worker thread running timers, if it is running.
+    timer_mgr_->stopThread();
+
    // Close the command socket (if it exists).
    // Close the command socket (if it exists).
     CommandMgr::instance().closeCommandSocket();
     CommandMgr::instance().closeCommandSocket();
 
 

+ 18 - 9
src/bin/dhcp6/ctrl_dhcp6_srv.h

@@ -18,6 +18,7 @@
 #include <asiolink/asiolink.h>
 #include <asiolink/asiolink.h>
 #include <cc/data.h>
 #include <cc/data.h>
 #include <cc/command_interpreter.h>
 #include <cc/command_interpreter.h>
+#include <dhcpsrv/timer_mgr.h>
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcp6/dhcp6_srv.h>
 
 
 namespace isc {
 namespace isc {
@@ -101,12 +102,7 @@ public:
         return (server_);
         return (server_);
     }
     }
 
 
-protected:
-    /// @brief Static pointer to the sole instance of the DHCP server.
-    ///
-    /// This is required for config and command handlers to gain access to
-    /// the server. Some of them need to be static methods.
-    static ControlledDhcpv6Srv* server_;
+private:
 
 
     /// @brief Callback that will be called from iface_mgr when data
     /// @brief Callback that will be called from iface_mgr when data
     /// is received over control socket.
     /// is received over control socket.
@@ -116,9 +112,6 @@ protected:
     /// (that was sent from some yet unspecified sender).
     /// (that was sent from some yet unspecified sender).
     static void sessionReader(void);
     static void sessionReader(void);
 
 
-    /// @brief IOService object, used for all ASIO operations.
-    isc::asiolink::IOService io_service_;
-
     /// @brief handler for processing 'shutdown' command
     /// @brief handler for processing 'shutdown' command
     ///
     ///
     /// This handler processes shutdown command, which initializes shutdown
     /// This handler processes shutdown command, which initializes shutdown
@@ -156,6 +149,22 @@ protected:
     isc::data::ConstElementPtr
     isc::data::ConstElementPtr
     commandConfigReloadHandler(const std::string& command,
     commandConfigReloadHandler(const std::string& command,
                                isc::data::ConstElementPtr args);
                                isc::data::ConstElementPtr args);
+
+    /// @brief Static pointer to the sole instance of the DHCP server.
+    ///
+    /// This is required for config and command handlers to gain access to
+    /// the server. Some of them need to be static methods.
+    static ControlledDhcpv6Srv* server_;
+
+    /// @brief IOService object, used for all ASIO operations.
+    isc::asiolink::IOService io_service_;
+
+    /// @brief Instance of the @c TimerMgr.
+    ///
+    /// Shared pointer to the instance of timer @c TimerMgr is held here to
+    /// make sure that the @c TimerMgr outlives instance of this class.
+    TimerMgrPtr timer_mgr_;
+
 };
 };
 
 
 }; // namespace isc::dhcp
 }; // namespace isc::dhcp

+ 106 - 1
src/bin/dhcp6/tests/dhcp6_process_tests.sh.in

@@ -16,6 +16,8 @@
 CFG_FILE=@abs_top_builddir@/src/bin/dhcp6/tests/test_config.json
 CFG_FILE=@abs_top_builddir@/src/bin/dhcp6/tests/test_config.json
 # Path to the Kea log file.
 # Path to the Kea log file.
 LOG_FILE=@abs_top_builddir@/src/bin/dhcp6/tests/test.log
 LOG_FILE=@abs_top_builddir@/src/bin/dhcp6/tests/test.log
+# Path to the Kea lease file.
+LEASE_FILE=@abs_top_builddir@/src/bin/dhcp6/tests/test_leases.csv
 # Expected version
 # Expected version
 EXPECTED_VERSION="@PACKAGE_VERSION@"
 EXPECTED_VERSION="@PACKAGE_VERSION@"
 # Kea configuration to be stored in the configuration file.
 # Kea configuration to be stored in the configuration file.
@@ -31,7 +33,9 @@ CONFIG="{
         \"lease-database\":
         \"lease-database\":
         {
         {
             \"type\": \"memfile\",
             \"type\": \"memfile\",
-            \"persist\": false
+            \"name\": \"$LEASE_FILE\",
+            \"persist\": false,
+            \"lfc-interval\": 0
         },
         },
         \"subnet6\": [
         \"subnet6\": [
         {
         {
@@ -277,9 +281,110 @@ returned %d."
     test_finish 0
     test_finish 0
 }
 }
 
 
+# This test verifies that DHCPv6 can be configured to run lease file cleanup
+# periodially.
+lfc_timer_test() {
+    # Log the start of the test and print test name.
+    test_start "dhcpv6_srv.lfc_timer_test"
+    # Remove dangling Kea instances and remove log files.
+    cleanup
+    # Create a configuration with the LFC enabled, by replacing the section
+    # with the lfc-interval and persist parameters.
+    LFC_CONFIG=$(printf "${CONFIG}" | sed -e 's/\"lfc-interval\": 0/\"lfc-interval\": 1/g' \
+                        | sed -e 's/\"persist\": false/\"persist\": true/g')
+    # Create new configuration file.
+    create_config "${LFC_CONFIG}"
+    # Instruct Kea to log to the specific file.
+    set_logger
+    # Start Kea.
+    start_kea ${bin_path}/${bin}
+    # Wait up to 20s for Kea to start.
+    wait_for_kea 20
+    if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
+        printf "ERROR: timeout waiting for Kea to start.\n"
+        clean_exit 1
+    fi
+
+    # Check if it is still running. It could have terminated (e.g. as a result
+    # of configuration failure).
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: expected one Kea process to be started. Found %d processes\
+ started.\n" ${_GET_PIDS_NUM}
+        clean_exit 1
+    fi
+
+    # Check if Kea emits the log message indicating that LFC is started.
+    wait_for_message 10 "DHCPSRV_MEMFILE_LFC_EXECUTE" 1
+    if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
+        printf "ERROR: Server did not execute LFC.\n"
+        clean_exit 1
+    fi
+
+    # Give it a short time to run.
+    sleep 1
+
+    # Modify the interval.
+    LFC_CONFIG=$(printf "${CONFIG}" | sed -e 's/\"lfc-interval\": 1/\"lfc-interval\": 2/g')
+    # Create new configuration file.
+    create_config "${LFC_CONFIG}"
+
+    # Reconfigure the server with SIGHUP.
+    send_signal 1 ${bin}
+
+    # There should be two occurrences of the DHCP4_CONFIG_COMPLETE messages.
+    # Wait for it up to 10s.
+    wait_for_message 10 "DHCP6_CONFIG_COMPLETE" 2
+
+    # After receiving SIGHUP the server should get reconfigured and the
+    # reconfiguration should be noted in the log file. We should now
+    # have two configurations logged in the log file.
+    if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
+        printf "ERROR: server hasn't been reconfigured.\n"
+        clean_exit 1
+    else
+        printf "Server successfully reconfigured.\n"
+    fi
+
+    # Make sure the server is still operational.
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: Kea process was killed when attempting reconfiguration.\n"
+        clean_exit 1
+    fi
+
+    # Wait for the LFC to run the second time.
+    wait_for_message 10 "DHCPSRV_MEMFILE_LFC_EXECUTE" 2
+    if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
+        printf "ERROR: Server did not execute LFC.\n"
+        clean_exit 1
+    fi
+
+    # Send signal to Kea SIGTERM
+    send_signal 15 ${bin}
+
+    # Wait up to 10s for the server's graceful shutdown. The graceful shut down
+    # should be recorded in the log file with the appropriate message.
+    wait_for_message 10 "DHCP6_SHUTDOWN" 1
+    if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
+        printf "ERROR: Server did not record shutdown in the log.\n"
+        clean_exit 1
+    fi
+
+    # Make sure the server is down.
+    wait_for_server_down 5 ${bin}
+    assert_eq 1 ${_WAIT_FOR_SERVER_DOWN} \
+        "Expected wait_for_server_down return %d, returned %d"
+
+    # All ok. Shut down Kea and exit.
+    test_finish 0
+}
+
 server_pid_file_test "${CONFIG}" DHCP6_ALREADY_RUNNING
 server_pid_file_test "${CONFIG}" DHCP6_ALREADY_RUNNING
 dynamic_reconfiguration_test
 dynamic_reconfiguration_test
 shutdown_test "dhcpv6.sigterm_test" 15
 shutdown_test "dhcpv6.sigterm_test" 15
 shutdown_test "dhcpv6.sigint_test" 2
 shutdown_test "dhcpv6.sigint_test" 2
 version_test "dhcpv6.version"
 version_test "dhcpv6.version"
 logger_vars_test "dhcpv6.variables"
 logger_vars_test "dhcpv6.variables"
+lfc_timer_test
+