]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#892] create pkt thread pool and handle processing using multiple threads
authorRazvan Becheriu <razvan@isc.org>
Wed, 5 Feb 2020 12:15:07 +0000 (14:15 +0200)
committerRazvan Becheriu <razvan@isc.org>
Fri, 21 Feb 2020 15:41:31 +0000 (17:41 +0200)
12 files changed:
src/bin/dhcp4/ctrl_dhcp4_srv.cc
src/bin/dhcp4/ctrl_dhcp4_srv.h
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp4/dhcp4_srv.h
src/bin/dhcp4/main.cc
src/bin/dhcp6/ctrl_dhcp6_srv.cc
src/bin/dhcp6/ctrl_dhcp6_srv.h
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/main.cc
src/lib/dhcpsrv/srv_config.cc
src/lib/dhcpsrv/srv_config.h

index c5f4931330b6e758725ac7a299f5dabfa60f3bc3..08efdf03b95170511c45cdaced41ecc0f84da37b 100644 (file)
@@ -5,30 +5,34 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 #include <config.h>
-#include <cc/data.h>
+
 #include <cc/command_interpreter.h>
+#include <cc/data.h>
+#include <cfgrpt/config_report.h>
 #include <config/command_mgr.h>
 #include <dhcp/libdhcp++.h>
-#include <dhcpsrv/cfgmgr.h>
-#include <dhcpsrv/cfg_db_access.h>
 #include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp4/dhcp4to6_ipc.h>
 #include <dhcp4/json_config_parser.h>
 #include <dhcp4/parser_context.h>
+#include <dhcpsrv/cfg_db_access.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/db_type.h>
 #include <hooks/hooks.h>
 #include <hooks/hooks_manager.h>
 #include <stats/stats_mgr.h>
-#include <cfgrpt/config_report.h>
 #include <signal.h>
+
 #include <sstream>
 
 using namespace isc::config;
-using namespace isc::db;
 using namespace isc::data;
+using namespace isc::db;
 using namespace isc::dhcp;
 using namespace isc::hooks;
 using namespace isc::stats;
+using namespace isc::util;
 using namespace std;
 
 namespace {
@@ -124,8 +128,6 @@ ControlledDhcpv4Srv::loadConfigFile(const std::string& file_name) {
     // configuration from a JSON file.
 
     isc::data::ConstElementPtr json;
-    isc::data::ConstElementPtr dhcp4;
-    isc::data::ConstElementPtr logger;
     isc::data::ConstElementPtr result;
 
     // Basic sanity check: file name must not be empty.
@@ -204,7 +206,6 @@ ControlledDhcpv4Srv::commandShutdownHandler(const string&, ConstElementPtr) {
 
 ConstElementPtr
 ControlledDhcpv4Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
-
     /// @todo delete any stored CalloutHandles referring to the old libraries
     /// Get list of currently loaded libraries and reload them.
     HookLibsCollection loaded = HooksManager::getLibraryInfo();
@@ -223,7 +224,6 @@ ControlledDhcpv4Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
 ConstElementPtr
 ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
                                                 ConstElementPtr /*args*/) {
-
     // Get configuration file name.
     std::string file = ControlledDhcpv4Srv::getInstance()->getConfigFile();
     try {
@@ -269,6 +269,7 @@ ControlledDhcpv4Srv::commandConfigWriteHandler(const string&,
 
     if (filename.empty()) {
         // filename parameter was not specified, so let's use whatever we remember
+        // from the command-line
         filename = getConfigFile();
     }
 
@@ -303,7 +304,7 @@ ControlledDhcpv4Srv::commandConfigWriteHandler(const string&,
 ConstElementPtr
 ControlledDhcpv4Srv::commandConfigSetHandler(const string&,
                                              ConstElementPtr args) {
-    const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
+    const int status_code = CONTROL_RESULT_ERROR;
     ConstElementPtr dhcp4;
     string message;
 
@@ -618,6 +619,16 @@ ControlledDhcpv4Srv::processCommand(const string& command,
         return (no_srv);
     }
 
+    if (Dhcpv4Srv::threadCount()) {
+        if (srv->pkt_thread_pool_.size()) {
+            srv->pkt_thread_pool_.stop();
+        }
+        MultiThreadingMgr::instance().setMode(true);
+        srv->pkt_thread_pool_.start(Dhcpv4Srv::threadCount());
+    } else {
+        MultiThreadingMgr::instance().setMode(false);
+    }
+
     try {
         if (command == "shutdown") {
             return (srv->commandShutdownHandler(command, args));
@@ -776,6 +787,7 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
         return (isc::config::createAnswer(1, err.str()));
     }
 
+    // Setup config backend polling, if configured for it.
     auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
     if (ctl_info) {
         long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
@@ -966,8 +978,8 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
         CommandMgr::instance().deregisterCommand("build-report");
         CommandMgr::instance().deregisterCommand("config-backend-pull");
         CommandMgr::instance().deregisterCommand("config-get");
-        CommandMgr::instance().deregisterCommand("config-reload");
         CommandMgr::instance().deregisterCommand("config-set");
+        CommandMgr::instance().deregisterCommand("config-reload");
         CommandMgr::instance().deregisterCommand("config-test");
         CommandMgr::instance().deregisterCommand("config-write");
         CommandMgr::instance().deregisterCommand("dhcp-disable");
@@ -995,8 +1007,8 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
         ;
     }
 
-    server_ = NULL; // forget this instance. Noone should call any handlers at
-                    // this stage.
+    server_ = NULL; // forget this instance. There should be no callback anymore
+                    // at this stage anyway.
 }
 
 void ControlledDhcpv4Srv::sessionReader(void) {
@@ -1133,5 +1145,5 @@ ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
     }
 }
 
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+}  // namespace dhcp
+}  // namespace isc
index 0111c9f7b7c745307d3037896f7bec7437849bb0..3242028fcd53e9b14ec236f0abd1154584760576 100644 (file)
@@ -33,7 +33,7 @@ public:
                         uint16_t client_port = 0);
 
     /// @brief Destructor.
-    ~ControlledDhcpv4Srv();
+    virtual ~ControlledDhcpv4Srv();
 
     /// @brief Initializes the server.
     ///
@@ -43,12 +43,12 @@ public:
     /// This method may throw if initialization fails.
     void init(const std::string& config_file);
 
-    /// @brief Loads specific config file
+    /// @brief Loads specific configuration file
     ///
     /// This utility method is called whenever we know a filename of the config
     /// and need to load it. It calls config-set command once the content of
     /// the file has been loaded and verified to be a sane JSON configuration.
-    /// config-set handler will process the config file (load it as current
+    /// config-set handler will process the config file (apply it as current
     /// configuration).
     ///
     /// @param file_name name of the file to be loaded
@@ -121,8 +121,8 @@ public:
         return (server_);
     }
 
-
 private:
+
     /// @brief Callback that will be called from iface_mgr when data
     /// is received over control socket.
     ///
@@ -249,7 +249,6 @@ private:
     commandDhcpEnableHandler(const std::string& command,
                              isc::data::ConstElementPtr args);
 
-
     /// @Brief handler for processing 'version-get' command
     ///
     /// This handler processes version-get command, which returns
@@ -416,7 +415,7 @@ private:
     /// @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
+    /// the server. Some of them need to be static methods.
     static ControlledDhcpv4Srv* server_;
 
     /// @brief IOService object, used for all ASIO operations.
@@ -429,7 +428,7 @@ private:
     TimerMgrPtr timer_mgr_;
 };
 
-}; // namespace isc::dhcp
-}; // namespace isc
+}  // namespace dhcp
+}  // namespace isc
 
 #endif
index f671fe3ae1a992dce58cc8c51b47548935e63e6e..bf1ff3a4871b66db43cf112cb01bf13406db3c2d 100644 (file)
@@ -39,7 +39,6 @@
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/subnet_selector.h>
 #include <dhcpsrv/utils.h>
-#include <dhcpsrv/utils.h>
 #include <eval/evaluate.h>
 #include <eval/eval_messages.h>
 #include <hooks/callout_handle.h>
@@ -47,7 +46,6 @@
 #include <hooks/hooks_manager.h>
 #include <stats/stats_mgr.h>
 #include <util/strutil.h>
-#include <stats/stats_mgr.h>
 #include <log/logger.h>
 #include <cryptolink/cryptolink.h>
 #include <cfgrpt/config_report.h>
@@ -80,6 +78,7 @@ using namespace isc::dhcp_ddns;
 using namespace isc::hooks;
 using namespace isc::log;
 using namespace isc::stats;
+using namespace isc::util;
 using namespace std;
 
 namespace {
@@ -102,8 +101,8 @@ struct Dhcp4Hooks {
         hook_index_pkt4_receive_      = HooksManager::registerHook("pkt4_receive");
         hook_index_subnet4_select_    = HooksManager::registerHook("subnet4_select");
         hook_index_leases4_committed_ = HooksManager::registerHook("leases4_committed");
-        hook_index_pkt4_send_         = HooksManager::registerHook("pkt4_send");
         hook_index_lease4_release_    = HooksManager::registerHook("lease4_release");
+        hook_index_pkt4_send_         = HooksManager::registerHook("pkt4_send");
         hook_index_buffer4_send_      = HooksManager::registerHook("buffer4_send");
         hook_index_lease4_decline_    = HooksManager::registerHook("lease4_decline");
         hook_index_host4_identifier_  = HooksManager::registerHook("host4_identifier");
@@ -209,7 +208,7 @@ Dhcpv4Exchange::Dhcpv4Exchange(const AllocEnginePtr& alloc_engine,
             .arg(query_->getLabel())
             .arg(classes.toText());
     }
-};
+}
 
 void
 Dhcpv4Exchange::initResponse() {
@@ -470,14 +469,15 @@ const std::string Dhcpv4Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
 
 Dhcpv4Srv::Dhcpv4Srv(uint16_t server_port, uint16_t client_port,
                      const bool use_bcast, const bool direct_response_desired)
-    : io_service_(new IOService()), shutdown_(true), alloc_engine_(),
-      use_bcast_(use_bcast), server_port_(server_port),
-      client_port_(client_port),
+    : io_service_(new IOService()), server_port_(server_port),
+      client_port_(client_port), shutdown_(true),
+      alloc_engine_(), use_bcast_(use_bcast),
       network_state_(new NetworkState(NetworkState::DHCPv4)),
       cb_control_(new CBControlDHCPv4()) {
 
     LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET)
         .arg(server_port);
+
     try {
         // Port 0 is used for testing purposes where we don't open broadcast
         // capable sockets. So, set the packet filter handling direct traffic
@@ -801,6 +801,11 @@ Dhcpv4Srv::run() {
         }
     }
 
+    // destroying the thread pool
+    if (Dhcpv4Srv::threadCount()) {
+        pkt_thread_pool_.reset();
+    }
+
     return (true);
 }
 
@@ -811,6 +816,17 @@ Dhcpv4Srv::run_one() {
     Pkt4Ptr rsp;
 
     try {
+
+        // Do not read more packets from socket if there are enough
+        // packets to be processed in the packet thread pool queue
+        const int max_queued_pkt_per_thread = Dhcpv4Srv::maxThreadQueueSize();
+        const auto queue_full_wait = std::chrono::milliseconds(1);
+        size_t pkt_queue_size = pkt_thread_pool_.count();
+        if (pkt_queue_size >= Dhcpv4Srv::threadCount() *
+            max_queued_pkt_per_thread) {
+            return;
+        }
+
         // Set select() timeout to 1s. This value should not be modified
         // because it is important that the select() returns control
         // frequently so as the IOService can be polled for ready handlers.
@@ -884,9 +900,33 @@ Dhcpv4Srv::run_one() {
             .arg(query->getLabel());
         return;
     } else {
-        processPacket(query, rsp);
+        if (Dhcpv4Srv::threadCount()) {
+            typedef function<void()> CallBack;
+            boost::shared_ptr<CallBack> call_back =
+                boost::make_shared<CallBack>(std::bind(&Dhcpv4Srv::processPacketAndSendResponseNoThrow,
+                                                       this, query, rsp));
+            pkt_thread_pool_.add(call_back);
+        } else {
+            processPacketAndSendResponse(query, rsp);
+        }
     }
+}
 
+void
+Dhcpv4Srv::processPacketAndSendResponseNoThrow(Pkt4Ptr& query, Pkt4Ptr& rsp) {
+    try {
+        processPacketAndSendResponse(query, rsp);
+    } catch (const std::exception& e) {
+        LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_STD_EXCEPTION)
+            .arg(e.what());
+    } catch (...) {
+        LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_EXCEPTION);
+    }
+}
+
+void
+Dhcpv4Srv::processPacketAndSendResponse(Pkt4Ptr& query, Pkt4Ptr& rsp) {
+    processPacket(query, rsp);
     if (!rsp) {
         return;
     }
@@ -3800,6 +3840,23 @@ int Dhcpv4Srv::getHookIndexLease4Decline() {
     return (Hooks.hook_index_lease4_decline_);
 }
 
+uint32_t Dhcpv4Srv::threadCount() {
+    uint32_t sys_threads = CfgMgr::instance().getCurrentCfg()->getServerThreadCount();
+    if (sys_threads) {
+        return sys_threads;
+    }
+    sys_threads = std::thread::hardware_concurrency();
+    return sys_threads * 0;
+}
+
+uint32_t Dhcpv4Srv::maxThreadQueueSize() {
+    uint32_t max_thread_queue_size = CfgMgr::instance().getCurrentCfg()->getServerMaxThreadQueueSize();
+    if (max_thread_queue_size) {
+        return max_thread_queue_size;
+    }
+    return 4;
+}
+
 void Dhcpv4Srv::discardPackets() {
     // Clear any packets held by the callhout handle store and
     // all parked packets
index 13265a5e29521b73610193a9d603a62f05094d7d..6789837babc9906c28d50985d825a2f8a06ff8a6 100644 (file)
@@ -9,23 +9,22 @@
 
 #include <asiolink/io_service.h>
 #include <dhcp/dhcp4.h>
-#include <dhcp/pkt4.h>
 #include <dhcp/option.h>
 #include <dhcp/option_string.h>
 #include <dhcp/option4_client_fqdn.h>
 #include <dhcp/option_custom.h>
+#include <dhcp/pkt4.h>
 #include <dhcp_ddns/ncr_msg.h>
 #include <dhcpsrv/alloc_engine.h>
+#include <dhcpsrv/callout_handle_store.h>
 #include <dhcpsrv/cb_ctl_dhcp4.h>
 #include <dhcpsrv/cfg_option.h>
-#include <dhcpsrv/callout_handle_store.h>
 #include <dhcpsrv/d2_client_mgr.h>
 #include <dhcpsrv/network_state.h>
 #include <dhcpsrv/subnet.h>
 #include <hooks/callout_handle.h>
 #include <process/daemon.h>
-
-#include <boost/noncopyable.hpp>
+#include <util/thread_pool.h>
 
 #include <functional>
 #include <iostream>
@@ -164,12 +163,16 @@ private:
 
     /// @brief Pointer to the allocation engine used by the server.
     AllocEnginePtr alloc_engine_;
+
     /// @brief Pointer to the DHCPv4 message sent by the client.
     Pkt4Ptr query_;
+
     /// @brief Pointer to the DHCPv4 message to be sent to the client.
     Pkt4Ptr resp_;
+
     /// @brief Context for use with allocation engine.
     AllocEngine::ClientContext4Ptr context_;
+
     /// @brief Configured option list.
     /// @note The configured option list is an *ordered* list of
     /// @c CfgOption objects used to append options to the response.
@@ -234,9 +237,9 @@ public:
     /// @brief Destructor. Used during DHCPv4 service shutdown.
     virtual ~Dhcpv4Srv();
 
-    /// @brief Checks if the server is running in a test mode.
+    /// @brief Checks if the server is running in unit test mode.
     ///
-    /// @return true if the server is running in the test mode,
+    /// @return true if the server is running in unit test mode,
     /// false otherwise.
     bool inTestMode() const {
         return (server_port_ == 0);
@@ -265,6 +268,12 @@ public:
     /// redeclaration/redefinition. @ref isc::process::Daemon::getVersion()
     static std::string getVersion(bool extended);
 
+    /// @brief returns Kea DHCPv4 server thread count.
+    static uint32_t threadCount();
+
+    /// @brief returns Kea DHCPv4 server max thread queue size.
+    static uint32_t maxThreadQueueSize();
+
     /// @brief Main server processing loop.
     ///
     /// Main server processing loop. Call the processing step routine
@@ -280,6 +289,24 @@ public:
     /// a response.
     void run_one();
 
+    /// @brief Process a single incoming DHCPv4 packet and sends the response.
+    ///
+    /// It verifies correctness of the passed packet, call per-type processXXX
+    /// methods, generates appropriate answer, sends the answer to the client.
+    ///
+    /// @param query A pointer to the packet to be processed.
+    /// @param rsp A pointer to the response
+    void processPacketAndSendResponse(Pkt4Ptr& query, Pkt4Ptr& rsp);
+
+    /// @brief Process a single incoming DHCPv4 packet and sends the response.
+    ///
+    /// It verifies correctness of the passed packet, call per-type processXXX
+    /// methods, generates appropriate answer, sends the answer to the client.
+    ///
+    /// @param query A pointer to the packet to be processed.
+    /// @param rsp A pointer to the response
+    void processPacketAndSendResponseNoThrow(Pkt4Ptr& query, Pkt4Ptr& rsp);
+
     /// @brief Process a single incoming DHCPv4 packet.
     ///
     /// It verifies correctness of the passed packet, call per-type processXXX
@@ -351,7 +378,9 @@ public:
                                       NameChangeSender::Result result,
                                       dhcp_ddns::NameChangeRequestPtr& ncr);
 
-    /// @brief Discard all in-progress packets
+    /// @brief Discards cached and parked packets
+    /// Clears the call_handle store and packet parking lots
+    /// of all packets.  Called during reconfigure and shutdown.
     void discardPackets();
 
 protected:
@@ -879,10 +908,6 @@ protected:
                                           bool& drop,
                                           bool sanity_only = false) const;
 
-    /// indicates if shutdown is in progress. Setting it to true will
-    /// initiate server shutdown procedure.
-    volatile bool shutdown_;
-
     /// @brief dummy wrapper around IfaceMgr::receive4
     ///
     /// This method is useful for testing purposes, where its replacement
@@ -961,11 +986,6 @@ protected:
     void processPacketBufferSend(hooks::CalloutHandlePtr& callout_handle,
                                  Pkt4Ptr& rsp);
 
-    /// @brief Allocation Engine.
-    /// Pointer to the allocation engine that we are currently using
-    /// It must be a pointer, because we will support changing engines
-    /// during normal operation (e.g. to use different allocators)
-    boost::shared_ptr<AllocEngine> alloc_engine_;
 
 private:
 
@@ -984,17 +1004,27 @@ private:
     /// @return Option that contains netmask information
     static OptionPtr getNetmaskOption(const Subnet4Ptr& subnet);
 
-    /// Should broadcast be enabled on sockets (if true).
-    bool use_bcast_;
-
 protected:
 
     /// UDP port number on which server listens.
     uint16_t server_port_;
 
-    /// UDP port number to which server sends responses.
+    /// UDP port number to which server sends all responses.
     uint16_t client_port_;
 
+    /// Indicates if shutdown is in progress. Setting it to true will
+    /// initiate server shutdown procedure.
+    volatile bool shutdown_;
+
+    /// @brief Allocation Engine.
+    /// Pointer to the allocation engine that we are currently using
+    /// It must be a pointer, because we will support changing engines
+    /// during normal operation (e.g. to use different allocators)
+    boost::shared_ptr<AllocEngine> alloc_engine_;
+
+    /// Should broadcast be enabled on sockets (if true).
+    bool use_bcast_;
+
     /// @brief Holds information about disabled DHCP service and/or
     /// disabled subnet/network scopes.
     NetworkStatePtr network_state_;
@@ -1002,6 +1032,9 @@ protected:
     /// @brief Controls access to the configuration backends.
     CBControlDHCPv4Ptr cb_control_;
 
+    /// @brief Packet processing thread pool
+    isc::util::ThreadPool<std::function<void()>> pkt_thread_pool_;
+
 public:
     /// Class methods for DHCPv4-over-DHCPv6 handler
 
@@ -1042,7 +1075,7 @@ public:
     static int getHookIndexLease4Decline();
 };
 
-}; // namespace isc::dhcp
-}; // namespace isc
+}  // namespace dhcp
+}  // namespace isc
 
 #endif // DHCP4_SRV_H
index a6b70ef803ed668772918280663e8c83cadda0d9..9c47d36af4281df61148279ea7c78d5a3a361f37 100644 (file)
@@ -7,15 +7,16 @@
 #include <config.h>
 #include <kea_version.h>
 
+#include <cfgrpt/config_report.h>
 #include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp4/parser_context.h>
 #include <dhcp4/json_config_parser.h>
-#include <cc/command_interpreter.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <exceptions/exceptions.h>
 #include <log/logger_support.h>
 #include <log/logger_manager.h>
-#include <cfgrpt/config_report.h>
+#include <process/daemon.h>
 
 #include <boost/lexical_cast.hpp>
 
@@ -31,6 +32,9 @@ using namespace std;
 /// instantiates ControlledDhcpv4Srv class that is responsible for establishing
 /// connection with msgq (receiving commands and configuration) and also
 /// creating Dhcpv4 server object as well.
+///
+/// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
+/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
 
 namespace {
 
@@ -55,9 +59,11 @@ usage() {
          << "(useful for testing only)" << endl;
     cerr << "  -P number: specify non-standard client port number 1-65535 "
          << "(useful for testing only)" << endl;
+    cerr << "  -N number: specify thread count 0-65535 "
+         << "(0 means multi-threading disabled)" << endl;
     exit(EXIT_FAILURE);
 }
-} // end of anonymous namespace
+}  // namespace
 
 int
 main(int argc, char* argv[]) {
@@ -66,6 +72,8 @@ main(int argc, char* argv[]) {
     int server_port_number = DHCP4_SERVER_PORT;
     // Not zero values are useful for testing only.
     int client_port_number = 0;
+    // Number of threads. 0 means multi-threading disabled
+    int thread_count = 0;
     bool verbose_mode = false; // Should server be verbose?
     bool check_mode = false;   // Check syntax
 
@@ -98,7 +106,7 @@ main(int argc, char* argv[]) {
             config_file = optarg;
             break;
 
-        case 'p':
+        case 'p': // server port number
             try {
                 server_port_number = boost::lexical_cast<int>(optarg);
             } catch (const boost::bad_lexical_cast &) {
@@ -113,7 +121,7 @@ main(int argc, char* argv[]) {
             }
             break;
 
-        case 'P':
+        case 'P': // client port number
             try {
                 client_port_number = boost::lexical_cast<int>(optarg);
             } catch (const boost::bad_lexical_cast &) {
@@ -128,6 +136,21 @@ main(int argc, char* argv[]) {
             }
             break;
 
+        case 'N': // number of threads
+            try {
+                thread_count = boost::lexical_cast<int>(optarg);
+            } catch (const boost::bad_lexical_cast &) {
+                cerr << "Failed to parse thread count number: [" << optarg
+                     << "], 0-65535 allowed." << endl;
+                usage();
+            }
+            if (thread_count < 0 || thread_count > 65535) {
+                cerr << "Failed to parse thread count number: [" << optarg
+                     << "], 0-65535 allowed." << endl;
+                usage();
+            }
+            break;
+
         default:
             usage();
         }
@@ -138,7 +161,6 @@ main(int argc, char* argv[]) {
         usage();
     }
 
-
     // Configuration file is required.
     if (config_file.empty()) {
         cerr << "Configuration file not specified." << endl;
@@ -150,7 +172,6 @@ main(int argc, char* argv[]) {
 
     if (check_mode) {
         try {
-
             // We need to initialize logging, in case any error messages are to be printed.
             // This is just a test, so we don't care about lockfile.
             setenv("KEA_LOCKFILE_DIR", "none", 0);
index 0aab657707c7ac20aa79e185c2c01e19cf63da06..4fde6fe2b02de88c54875f7e8e23d57358219afa 100644 (file)
@@ -5,30 +5,34 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 #include <config.h>
-#include <cc/data.h>
+
 #include <cc/command_interpreter.h>
+#include <cc/data.h>
+#include <cfgrpt/config_report.h>
 #include <config/command_mgr.h>
 #include <dhcp/libdhcp++.h>
-#include <dhcpsrv/cfgmgr.h>
-#include <dhcpsrv/cfg_db_access.h>
 #include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcp6/dhcp6_log.h>
 #include <dhcp6/dhcp6to4_ipc.h>
 #include <dhcp6/json_config_parser.h>
 #include <dhcp6/parser_context.h>
+#include <dhcpsrv/cfg_db_access.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/db_type.h>
 #include <hooks/hooks.h>
 #include <hooks/hooks_manager.h>
 #include <stats/stats_mgr.h>
-#include <cfgrpt/config_report.h>
 #include <signal.h>
+
 #include <sstream>
 
 using namespace isc::config;
-using namespace isc::db;
 using namespace isc::data;
+using namespace isc::db;
 using namespace isc::dhcp;
 using namespace isc::hooks;
 using namespace isc::stats;
+using namespace isc::util;
 using namespace std;
 
 namespace {
@@ -96,8 +100,6 @@ ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
     // configuration from a JSON file.
 
     isc::data::ConstElementPtr json;
-    isc::data::ConstElementPtr dhcp6;
-    isc::data::ConstElementPtr logger;
     isc::data::ConstElementPtr result;
 
     // Basic sanity check: file name must not be empty.
@@ -160,7 +162,6 @@ ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
     return (result);
 }
 
-
 void
 ControlledDhcpv6Srv::init(const std::string& file_name) {
     // Keep the call timestamp.
@@ -168,6 +169,7 @@ ControlledDhcpv6Srv::init(const std::string& file_name) {
 
     // Configure the server using JSON file.
     ConstElementPtr result = loadConfigFile(file_name);
+
     int rcode;
     ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
     if (rcode != 0) {
@@ -192,11 +194,10 @@ void ControlledDhcpv6Srv::cleanup() {
     // Nothing to do here. No need to disconnect from anything.
 }
 
-
 ConstElementPtr
 ControlledDhcpv6Srv::commandShutdownHandler(const string&, ConstElementPtr) {
-    if (ControlledDhcpv6Srv::server_) {
-        ControlledDhcpv6Srv::server_->shutdown();
+    if (ControlledDhcpv6Srv::getInstance()) {
+        ControlledDhcpv6Srv::getInstance()->shutdown();
     } else {
         LOG_WARN(dhcp6_logger, DHCP6_NOT_RUNNING);
         ConstElementPtr answer = isc::config::createAnswer(1, "Shutdown failure.");
@@ -378,6 +379,7 @@ ControlledDhcpv6Srv::commandConfigSetHandler(const string&,
     isc::config::parseAnswer(rcode, result);
     if (rcode == CONTROL_RESULT_SUCCESS) {
         CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
+
         // Use new configuration.
         CfgMgr::instance().commit();
     } else {
@@ -618,6 +620,16 @@ ControlledDhcpv6Srv::processCommand(const std::string& command,
         return (no_srv);
     }
 
+    if (Dhcpv6Srv::threadCount()) {
+        if (srv->pkt_thread_pool_.size()) {
+            srv->pkt_thread_pool_.stop();
+        }
+        MultiThreadingMgr::instance().setMode(true);
+        srv->pkt_thread_pool_.start(Dhcpv6Srv::threadCount());
+    } else {
+        MultiThreadingMgr::instance().setMode(false);
+    }
+
     try {
         if (command == "shutdown") {
             return (srv->commandShutdownHandler(command, args));
@@ -872,11 +884,11 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port,
                                          uint16_t client_port)
     : Dhcpv6Srv(server_port, client_port), io_service_(),
       timer_mgr_(TimerMgr::instance()) {
-    if (server_) {
+    if (getInstance()) {
         isc_throw(InvalidOperation,
                   "There is another Dhcpv6Srv instance already.");
     }
-    server_ = this; // remember this instance for use in callback
+    server_ = this; // remember this instance for later use in handlers
 
     // TimerMgr uses IO service to run asynchronous timers.
     TimerMgr::instance()->setIOService(getIOService());
@@ -1021,8 +1033,8 @@ ControlledDhcpv6Srv::~ControlledDhcpv6Srv() {
 void ControlledDhcpv6Srv::sessionReader(void) {
     // Process one asio event. If there are more events, iface_mgr will call
     // this callback more than once.
-    if (server_) {
-        server_->io_service_.run_one();
+    if (getInstance()) {
+        getInstance()->io_service_.run_one();
     }
 }
 
@@ -1061,12 +1073,13 @@ ControlledDhcpv6Srv::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
     if (reopened) {
         // Cancel the timer.
         if (TimerMgr::instance()->isTimerRegistered("Dhcp6DbReconnectTimer")) {
-            TimerMgr::instance()->cancel("Dhcp6DbReconnectTimer"); }
+            TimerMgr::instance()->cancel("Dhcp6DbReconnectTimer");
+        }
 
         // Set network state to service enabled
         network_state_->enableService();
 
-        // Toss the reconnct control, we're done with it
+        // Toss the reconnect control, we're done with it
         db_reconnect_ctl.reset();
     } else {
         if (!db_reconnect_ctl->checkRetries()) {
@@ -1084,7 +1097,7 @@ ControlledDhcpv6Srv::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
         if (!TimerMgr::instance()->isTimerRegistered("Dhcp6DbReconnectTimer")) {
             TimerMgr::instance()->registerTimer("Dhcp6DbReconnectTimer",
                             boost::bind(&ControlledDhcpv6Srv::dbReconnect, this,
-                            db_reconnect_ctl),
+                                        db_reconnect_ctl),
                             db_reconnect_ctl->retryInterval(),
                             asiolink::IntervalTimer::ONE_SHOT);
         }
@@ -1150,5 +1163,5 @@ ControlledDhcpv6Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
     }
 }
 
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+}  // namespace dhcp
+}  // namespace isc
index f4085fab90ac8547cadcfd9c29ef61a9ce049e18..951c39a40e2bab48036268032a0605457cc8f23c 100644 (file)
@@ -65,7 +65,7 @@ public:
     /// @brief Initiates shutdown procedure for the whole DHCPv6 server.
     void shutdown();
 
-    /// @brief command processor
+    /// @brief Command processor
     ///
     /// This method is uniform for all config backends. It processes received
     /// command (as a string + JSON arguments). Internally, it's just a
@@ -75,9 +75,9 @@ public:
     /// Currently supported commands are:
     /// - config-reload
     /// - config-test
-    /// - leases-reclaim
-    /// - libreload
     /// - shutdown
+    /// - libreload
+    /// - leases-reclaim
     /// ...
     ///
     /// @note It never throws.
@@ -89,7 +89,7 @@ public:
     static isc::data::ConstElementPtr
     processCommand(const std::string& command, isc::data::ConstElementPtr args);
 
-    /// @brief configuration processor
+    /// @brief Configuration processor
     ///
     /// This is a method for handling incoming configuration updates.
     /// This method should be called by all configuration backends when the
@@ -114,7 +114,7 @@ public:
     isc::data::ConstElementPtr
     checkConfig(isc::data::ConstElementPtr new_config);
 
-    /// @brief returns pointer to the sole instance of Dhcpv6Srv
+    /// @brief Returns pointer to the sole instance of Dhcpv6Srv
     ///
     /// @return server instance (may return NULL, if called before server is spawned)
     static ControlledDhcpv6Srv* getInstance() {
@@ -131,7 +131,7 @@ private:
     /// (that was sent from some yet unspecified sender).
     static void sessionReader(void);
 
-    /// @brief handler for processing 'shutdown' command
+    /// @brief Handler for processing 'shutdown' command
     ///
     /// This handler processes shutdown command, which initializes shutdown
     /// procedure.
@@ -143,7 +143,7 @@ private:
     commandShutdownHandler(const std::string& command,
                            isc::data::ConstElementPtr args);
 
-    /// @brief handler for processing 'libreload' command
+    /// @brief Handler for processing 'libreload' command
     ///
     /// This handler processes libreload command, which unloads all hook
     /// libraries and reloads them.
@@ -156,7 +156,7 @@ private:
     commandLibReloadHandler(const std::string& command,
                             isc::data::ConstElementPtr args);
 
-    /// @brief handler for processing 'config-reload' command
+    /// @brief Handler for processing 'config-reload' command
     ///
     /// This handler processes config-reload command, which processes
     /// configuration specified in args parameter.
@@ -348,7 +348,6 @@ private:
                               const bool remove_lease,
                               const uint16_t max_unwarned_cycles);
 
-
     /// @brief Deletes reclaimed leases and reschedules the timer.
     ///
     /// This is a wrapper method for @c AllocEngine::deleteExpiredReclaimed6.
@@ -373,6 +372,7 @@ private:
     ///
     /// If the maximum number of retries has been exhausted an error is logged
     /// and the server shuts down.
+    ///
     /// @param db_reconnect_ctl pointer to the ReconnectCtl containing the
     /// configured reconnect parameters
     ///
@@ -394,6 +394,8 @@ private:
     ///
     /// @param db_reconnect_ctl pointer to the ReconnectCtl containing the
     /// configured reconnect parameters
+    ///
+    /// @return false if reconnect is not configured, true otherwise
     bool dbLostCallback(db::ReconnectCtlPtr db_reconnect_ctl);
 
     /// @brief Callback invoked periodically to fetch configuration updates
@@ -426,7 +428,7 @@ private:
     TimerMgrPtr timer_mgr_;
 };
 
-}; // namespace isc::dhcp
-}; // namespace isc
+}  // namespace dhcp
+}  // namespace isc
 
 #endif
index ef4c2720298c20a7432ca940f4b651473ca8c058..a032398dd729b52787b117784fada6023fc9e545 100644 (file)
@@ -46,7 +46,6 @@
 #include <hooks/hooks_log.h>
 #include <hooks/hooks_manager.h>
 #include <stats/stats_mgr.h>
-
 #include <util/encode/hex.h>
 #include <util/io_utilities.h>
 #include <util/pointer_util.h>
@@ -472,6 +471,11 @@ bool Dhcpv6Srv::run() {
         }
     }
 
+    // destroying the thread pool
+    if (Dhcpv6Srv::threadCount()) {
+        pkt_thread_pool_.reset();
+    }
+
     return (true);
 }
 
@@ -481,6 +485,17 @@ void Dhcpv6Srv::run_one() {
     Pkt6Ptr rsp;
 
     try {
+
+        // Do not read more packets from socket if there are enough
+        // packets to be processed in the packet thread pool queue
+        const int max_queued_pkt_per_thread = Dhcpv6Srv::maxThreadQueueSize();
+        const auto queue_full_wait = std::chrono::milliseconds(1);
+        size_t pkt_queue_size = pkt_thread_pool_.count();
+        if (pkt_queue_size >= Dhcpv6Srv::threadCount() *
+            max_queued_pkt_per_thread) {
+            return;
+        }
+
         // Set select() timeout to 1s. This value should not be modified
         // because it is important that the select() returns control
         // frequently so as the IOService can be polled for ready handlers.
@@ -558,9 +573,33 @@ void Dhcpv6Srv::run_one() {
             .arg(query->getLabel());
         return;
     } else {
-        processPacket(query, rsp);
+        if (Dhcpv6Srv::threadCount()) {
+            typedef function<void()> CallBack;
+            boost::shared_ptr<CallBack> call_back =
+                boost::make_shared<CallBack>(std::bind(&Dhcpv6Srv::processPacketAndSendResponseNoThrow,
+                                                       this, query, rsp));
+            pkt_thread_pool_.add(call_back);
+        } else {
+            processPacketAndSendResponse(query, rsp);
+        }
+    }
+}
+
+void
+Dhcpv6Srv::processPacketAndSendResponseNoThrow(Pkt6Ptr& query, Pkt6Ptr& rsp) {
+    try {
+        processPacketAndSendResponse(query, rsp);
+    } catch (const std::exception& e) {
+        LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_STD_EXCEPTION)
+            .arg(e.what());
+    } catch (...) {
+        LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_EXCEPTION);
     }
+}
 
+void
+Dhcpv6Srv::processPacketAndSendResponse(Pkt6Ptr& query, Pkt6Ptr& rsp) {
+    processPacket(query, rsp);
     if (!rsp) {
         return;
     }
@@ -3997,6 +4036,23 @@ Dhcpv6Srv::requestedInORO(const Pkt6Ptr& query, const uint16_t code) const {
     return (false);
 }
 
+uint32_t Dhcpv6Srv::threadCount() {
+    uint32_t sys_threads = CfgMgr::instance().getCurrentCfg()->getServerThreadCount();
+    if (sys_threads) {
+        return sys_threads;
+    }
+    sys_threads = std::thread::hardware_concurrency();
+    return sys_threads * 0;
+}
+
+uint32_t Dhcpv6Srv::maxThreadQueueSize() {
+    uint32_t max_thread_queue_size = CfgMgr::instance().getCurrentCfg()->getServerMaxThreadQueueSize();
+    if (max_thread_queue_size) {
+        return max_thread_queue_size;
+    }
+    return 4;
+}
+
 void Dhcpv6Srv::discardPackets() {
     // Dump all of our current packets, anything that is mid-stream
     isc::dhcp::Pkt6Ptr pkt6ptr_empty;
index 80e42a47b11173eb41342934372ad3d789879baa..17c3121f7e96fe2615db7dda370a4f0b5c94174d 100644 (file)
@@ -8,13 +8,15 @@
 #define DHCPV6_SRV_H
 
 #include <asiolink/io_service.h>
-#include <dhcp_ddns/ncr_msg.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/duid.h>
 #include <dhcp/option.h>
+#include <dhcp/option_string.h>
 #include <dhcp/option6_client_fqdn.h>
 #include <dhcp/option6_ia.h>
+#include <dhcp/option_custom.h>
 #include <dhcp/option_definition.h>
+#include <dhcp_ddns/ncr_msg.h>
 #include <dhcp/pkt6.h>
 #include <dhcpsrv/alloc_engine.h>
 #include <dhcpsrv/callout_handle_store.h>
@@ -25,6 +27,7 @@
 #include <dhcpsrv/subnet.h>
 #include <hooks/callout_handle.h>
 #include <process/daemon.h>
+#include <util/thread_pool.h>
 
 #include <functional>
 #include <iostream>
@@ -51,12 +54,16 @@ public:
 
 /// @brief DHCPv6 server service.
 ///
-/// This class represents DHCPv6 server. It contains all
+/// This singleton class represents DHCPv6 server. It contains all
 /// top-level methods and routines necessary for server operation.
 /// In particular, it instantiates IfaceMgr, loads or generates DUID
 /// that is going to be used as server-identifier, receives incoming
 /// packets, processes them, manages leases assignment and generates
 /// appropriate responses.
+///
+/// This class does not support any controlling mechanisms directly.
+/// See the derived \ref ControlledDhcpv6Srv class for support for
+/// command and configuration updates over msgq.
 class Dhcpv6Srv : public process::Daemon {
 private:
 
@@ -79,10 +86,13 @@ public:
     /// Instantiates necessary services, required to run DHCPv6 server.
     /// In particular, creates IfaceMgr that will be responsible for
     /// network interaction. Will instantiate lease manager, and load
-    /// old or create new DUID.
+    /// old or create new DUID. It is possible to specify alternate
+    /// port on which DHCPv6 server will listen on and alternate port
+    /// where DHCPv6 server sends all responses to. Those are mostly useful
+    /// for testing purposes.
     ///
-    /// @param server_port port on which all sockets will listen
-    /// @param client_port port to which all responses will be sent
+    /// @param server_port specifies port number to listen on
+    /// @param client_port specifies port number to send to
     Dhcpv6Srv(uint16_t server_port = DHCP6_SERVER_PORT,
               uint16_t client_port = 0);
 
@@ -120,6 +130,12 @@ public:
     /// redeclaration/redefinition. @ref isc::process::Daemon::getVersion()
     static std::string getVersion(bool extended);
 
+    /// @brief returns Kea DHCPv6 server thread count.
+    static uint32_t threadCount();
+
+    /// @brief returns Kea DHCPv6 server max thread queue size.
+    static uint32_t maxThreadQueueSize();
+
     /// @brief Returns server-identifier option.
     ///
     /// @return server-id option
@@ -140,6 +156,24 @@ public:
     /// a response.
     void run_one();
 
+    /// @brief Process a single incoming DHCPv6 packet and sends the response.
+    ///
+    /// It verifies correctness of the passed packet, call per-type processXXX
+    /// methods, generates appropriate answer, sends the answer to the client.
+    ///
+    /// @param query A pointer to the packet to be processed.
+    /// @param rsp A pointer to the response
+    void processPacketAndSendResponse(Pkt6Ptr& query, Pkt6Ptr& rsp);
+
+    /// @brief Process a single incoming DHCPv6 packet and sends the response.
+    ///
+    /// It verifies correctness of the passed packet, call per-type processXXX
+    /// methods, generates appropriate answer, sends the answer to the client.
+    ///
+    /// @param query A pointer to the packet to be processed.
+    /// @param rsp A pointer to the response
+    void processPacketAndSendResponseNoThrow(Pkt6Ptr& query, Pkt6Ptr& rsp);
+
     /// @brief Process a single incoming DHCPv6 packet.
     ///
     /// It verifies correctness of the passed packet, call per-type processXXX
@@ -152,15 +186,21 @@ public:
     /// @brief Instructs the server to shut down.
     void shutdown();
 
+    ///
+    /// @name Public accessors returning values required to (re)open sockets.
+    ///
+    //@{
+    ///
     /// @brief Get UDP port on which server should listen.
     ///
-    /// Typically, server listens on UDP port 547. Other ports are only
-    /// used for testing purposes.
+    /// Typically, server listens on UDP port number 547. Other ports are used
+    /// for testing purposes only.
     ///
     /// @return UDP port on which server should listen.
     uint16_t getServerPort() const {
         return (server_port_);
     }
+    //@}
 
     /// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled.
     ///
@@ -1057,9 +1097,12 @@ protected:
 
     /// @brief Controls access to the configuration backends.
     CBControlDHCPv6Ptr cb_control_;
+
+    /// @brief Packet processing thread pool
+    isc::util::ThreadPool<std::function<void()>> pkt_thread_pool_;
 };
 
-}; // namespace isc::dhcp
-}; // namespace isc
+}  // namespace dhcp
+}  // namespace isc
 
 #endif // DHCP6_SRV_H
index 42946db9c63e03a5676f7797a38aa3e9665d04bb..89b4f46960b6b79fb6d50c3924c6da976b7c9bd4 100644 (file)
@@ -7,15 +7,15 @@
 #include <config.h>
 #include <kea_version.h>
 
+#include <cfgrpt/config_report.h>
 #include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcp6/dhcp6_log.h>
 #include <dhcp6/parser_context.h>
 #include <dhcp6/json_config_parser.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <exceptions/exceptions.h>
 #include <log/logger_support.h>
 #include <log/logger_manager.h>
-#include <exceptions/exceptions.h>
-#include <cfgrpt/config_report.h>
 #include <process/daemon.h>
 
 #include <boost/lexical_cast.hpp>
@@ -37,9 +37,8 @@ using namespace std;
 /// Dhcpv6Srv and other classes, see \ref dhcpv6Session.
 
 namespace {
-const char* const DHCP6_NAME = "kea-dhcp6";
 
-const char* const DHCP6_LOGGER_NAME = "kea-dhcp6";
+const char* const DHCP6_NAME = "kea-dhcp6";
 
 /// @brief Prints Kea Usage and exits
 ///
@@ -60,9 +59,11 @@ usage() {
          << "(useful for testing only)" << endl;
     cerr << "  -P number: specify non-standard client port number 1-65535 "
          << "(useful for testing only)" << endl;
+    cerr << "  -N number: specify thread count 0-65535 "
+         << "(0 means multi-threading disabled)" << endl;
     exit(EXIT_FAILURE);
 }
-} // end of anonymous namespace
+}  // namespace
 
 int
 main(int argc, char* argv[]) {
@@ -71,6 +72,8 @@ main(int argc, char* argv[]) {
     int server_port_number = DHCP6_SERVER_PORT;
     // Not zero values are useful for testing only.
     int client_port_number = 0;
+    // Number of threads. 0 means multi-threading disabled
+    int thread_count = 0;
     bool verbose_mode = false; // Should server be verbose?
     bool check_mode = false;   // Check syntax
 
@@ -133,6 +136,21 @@ main(int argc, char* argv[]) {
             }
             break;
 
+        case 'N': // number of threads
+            try {
+                thread_count = boost::lexical_cast<int>(optarg);
+            } catch (const boost::bad_lexical_cast &) {
+                cerr << "Failed to parse thread count number: [" << optarg
+                     << "], 0-65535 allowed." << endl;
+                usage();
+            }
+            if (thread_count < 0 || thread_count > 65535) {
+                cerr << "Failed to parse thread count number: [" << optarg
+                     << "], 0-65535 allowed." << endl;
+                usage();
+            }
+            break;
+
         default:
             usage();
         }
@@ -193,11 +211,8 @@ main(int argc, char* argv[]) {
                 cerr << "Error encountered: " << answer->stringValue() << endl;
                 return (EXIT_FAILURE);
             }
-
-
-            return (EXIT_SUCCESS);
         } catch (const std::exception& ex) {
-            cerr << "Syntax check failed with " << ex.what() << endl;
+            cerr << "Syntax check failed with: " << ex.what() << endl;
         }
         return (EXIT_FAILURE);
     }
@@ -207,11 +222,10 @@ main(int argc, char* argv[]) {
         // It is important that we set a default logger name because this name
         // will be used when the user doesn't provide the logging configuration
         // in the Kea configuration file.
-        Daemon::setDefaultLoggerName(DHCP6_LOGGER_NAME);
+        Daemon::setDefaultLoggerName(DHCP6_ROOT_LOGGER_NAME);
 
         // Initialize logging.  If verbose, we'll use maximum verbosity.
-        Daemon::loggerInit(DHCP6_LOGGER_NAME, verbose_mode);
-
+        Daemon::loggerInit(DHCP6_ROOT_LOGGER_NAME, verbose_mode);
         LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_START_INFO)
             .arg(getpid())
             .arg(server_port_number)
@@ -226,16 +240,14 @@ main(int argc, char* argv[]) {
         // Remember verbose-mode
         server.setVerbose(verbose_mode);
 
-        // Create our PID file
+        // Create our PID file.
         server.setProcName(DHCP6_NAME);
         server.setConfigFile(config_file);
         server.createPIDFile();
 
         try {
-            // Initialize the server, e.g. establish control session
-            // Read a configuration file
+            // Initialize the server.
             server.init(config_file);
-
         } catch (const std::exception& ex) {
 
             try {
@@ -245,8 +257,8 @@ main(int argc, char* argv[]) {
                 LOG_ERROR(dhcp6_logger, DHCP6_INIT_FAIL).arg(ex.what());
             } catch (...) {
                 // The exception thrown during the initialization could
-                // originate from logger subsystem. Therefore LOG_ERROR() may
-                // fail as well.
+                // originate from logger subsystem. Therefore LOG_ERROR()
+                // may fail as well.
                 cerr << "Failed to initialize server: " << ex.what() << endl;
             }
 
@@ -277,7 +289,6 @@ main(int argc, char* argv[]) {
         }
         ret = EXIT_FAILURE;
     } catch (const std::exception& ex) {
-
         // First, we print the error on stderr (that should always work)
         cerr << DHCP6_NAME << "Fatal error during start up: " << ex.what()
              << endl;
index d016bcbecf32cc46738cab8a4b4689eef7b5881f..b40c25a3ae956cefe8bf7d4ad94be7d796bb3826 100644 (file)
@@ -41,6 +41,8 @@ SrvConfig::SrvConfig()
       cfg_host_operations6_(CfgHostOperations::createConfig6()),
       class_dictionary_(new ClientClassDictionary()),
       decline_timer_(0), echo_v4_client_id_(true), dhcp4o6_port_(0),
+      server_threads_(0),
+      server_max_thread_queue_size_(0),
       d2_client_config_(new D2ClientConfig()),
       configured_globals_(Element::createMap()),
       cfg_consist_(new CfgConsistency()) {
@@ -59,6 +61,8 @@ SrvConfig::SrvConfig(const uint32_t sequence)
       cfg_host_operations6_(CfgHostOperations::createConfig6()),
       class_dictionary_(new ClientClassDictionary()),
       decline_timer_(0), echo_v4_client_id_(true), dhcp4o6_port_(0),
+      server_threads_(0),
+      server_max_thread_queue_size_(0),
       d2_client_config_(new D2ClientConfig()),
       configured_globals_(Element::createMap()),
       cfg_consist_(new CfgConsistency()) {
@@ -253,7 +257,6 @@ SrvConfig::mergeGlobals(SrvConfig& other) {
 
 void
 SrvConfig::removeStatistics() {
-
     // Removes statistics for v4 and v6 subnets
     getCfgSubnets4()->removeStatistics();
 
index efbe06aebf77e5c8ace76a19a2a00a0b78a0098f..3107ffeb2eb4f12be5b248f5fd922b80ec187589 100644 (file)
@@ -705,6 +705,34 @@ public:
         return (dhcp4o6_port_);
     }
 
+    /// @brief Sets the server thread count.
+    ///
+    /// @param threads value of the server thread count
+    void setServerThreadCount(uint32_t threads) {
+        server_threads_ = threads;
+    }
+
+    /// @brief Retrieves the server thread count.
+    ///
+    /// @return value of the server thread count
+    uint32_t getServerThreadCount() const {
+        return (server_threads_);
+    }
+
+    /// @brief Sets the server max thread queue size.
+    ///
+    /// @param size max thread queue size
+    void setServerMaxThreadQueueSize(uint32_t size) {
+        server_max_thread_queue_size_ = size;
+    }
+
+    /// @brief Retrieves the server max thread queue size.
+    ///
+    /// @return value of the max thread queue size
+    uint32_t getServerMaxThreadQueueSize() const {
+        return (server_max_thread_queue_size_);
+    }
+
     /// @brief Returns pointer to the D2 client configuration
     D2ClientConfigPtr getD2ClientConfig() {
         return (d2_client_config_);
@@ -923,6 +951,12 @@ private:
     /// this socket is bound and connected to this port and port + 1
     uint16_t dhcp4o6_port_;
 
+    /// @brief The server thread count.
+    uint32_t server_threads_;
+
+    /// @brief The server max thread queue size.
+    uint32_t server_max_thread_queue_size_;
+
     /// @brief Stores D2 client configuration
     D2ClientConfigPtr d2_client_config_;
 
@@ -943,7 +977,7 @@ typedef boost::shared_ptr<SrvConfig> SrvConfigPtr;
 typedef boost::shared_ptr<const SrvConfig> ConstSrvConfigPtr;
 //@}
 
-} // namespace isc::dhcp
-} // namespace isc
+}  // namespace dhcp
+}  // namespace isc
 
 #endif // DHCPSRV_CONFIG_H