Commit 00d6396b authored by Razvan Becheriu's avatar Razvan Becheriu

[#892] create pkt thread pool and handle processing using multiple threads

parent 694e1af0
......@@ -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
......@@ -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
......@@ -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
......
......@@ -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
......@@ -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);
......
......@@ -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 {