2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 05:27:55 +00:00

[#893] added multi-threading parameters

This commit is contained in:
Razvan Becheriu 2020-04-02 19:49:27 +03:00
parent 25ee29e289
commit 0ab220a3e3
24 changed files with 442 additions and 148 deletions

View File

@ -523,6 +523,22 @@
// When the maximum count is 0 the maximum age (in seconds) applies.
"statistic-default-sample-age": 60,
// By default Kea processes packets on a single thread (default 'false'
// value for this option). To enable multi-threading, this option can be
// set ('true' value).
"enable-multi-threading": false,
// When multi-threading is enabled, Kea will process packets on a number of
// multiple threads configurable through this option. The value must be a
// positive integer (0 means auto detect).
"packet-thread-pool-size": 0,
// When multi-threading is enabled, Kea will read packets from the interface
// and append a working item to the thread pool. This option configures the
// maximum number of items that can be queued for each processing thread.
// The value must be a positive integer (0 means unlimited).
"packet-thread-queue-size": 0,
// Governs how the Kea DHCPv4 server should deal with the invalid
// data received from the client.
"sanity-checks": {

View File

@ -464,6 +464,22 @@
// When the maximum count is 0 the maximum age (in seconds) applies.
"statistic-default-sample-age": 60,
// By default Kea processes packets on a single thread (default 'false'
// value for this option). To enable multi-threading, this option can be
// set ('true' value).
"enable-multi-threading": false,
// When multi-threading is enabled, Kea will process packets on a number of
// multiple threads configurable through this option. The value must be a
// positive integer (0 means auto detect).
"packet-thread-pool-size": 0,
// When multi-threading is enabled, Kea will read packets from the interface
// and append a working item to the thread pool. This option configures the
// maximum number of items that can be queued for each processing thread.
// The value must be a positive integer (0 means unlimited).
"packet-thread-queue-size": 0,
// Governs how the Kea DHCPv6 server should deal with the invalid
// data received from the client.
"sanity-checks": {

View File

@ -169,17 +169,20 @@ ControlledDhcpv4Srv::loadConfigFile(const std::string& file_name) {
"processCommand(\"config-set\", json)");
}
// command line parameters overwrite file and database configuration
bool enabled = false;
if (srv_thread_count >= 0) {
if (Dhcpv4Srv::srv_thread_count_ >= 0) {
enabled = true;
}
if (enabled) {
CfgMgr::instance().getCurrentCfg()->setServerThreadCount(srv_thread_count);
CfgMgr::instance().getCurrentCfg()->setServerMaxThreadQueueSize(4);
CfgMgr::instance().getCurrentCfg()->setPktThreadPoolSize(Dhcpv4Srv::srv_thread_count_);
CfgMgr::instance().getCurrentCfg()->setPktThreadQueueSize(0);
LOG_FATAL(dhcp4_logger, DHCP4_MULTI_THREADING_WARNING);
} else {
enabled = CfgMgr::instance().getCurrentCfg()->getEnableMultiThreading();
}
MultiThreadingMgr::instance().apply(enabled,
CfgMgr::instance().getCurrentCfg()->getServerThreadCount());
CfgMgr::instance().getCurrentCfg()->getPktThreadPoolSize());
// Now check is the returned result is successful (rcode=0) or not
// (see @ref isc::config::parseAnswer).
@ -204,7 +207,7 @@ ControlledDhcpv4Srv::loadConfigFile(const std::string& file_name) {
LOG_WARN(dhcp4_logger, DHCP4_MULTI_THREADING_INFO)
.arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
.arg(MultiThreadingMgr::instance().getPktThreadPoolSize())
.arg(CfgMgr::instance().getCurrentCfg()->getServerMaxThreadQueueSize());
.arg(CfgMgr::instance().getCurrentCfg()->getPktThreadQueueSize());
return (result);
}

View File

@ -1418,6 +1418,33 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"enable-multi-threading\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
return isc::dhcp::Dhcp4Parser::make_ENABLE_MULTI_THREADING(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("enable-multi-threading", driver.loc_);
}
}
\"packet-thread-pool-size\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
return isc::dhcp::Dhcp4Parser::make_PACKET_THREAD_POOL_SIZE(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("packet-thread-pool-size", driver.loc_);
}
}
\"packet-thread-queue-size\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
return isc::dhcp::Dhcp4Parser::make_PACKET_THREAD_QUEUE_SIZE(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("packet-thread-queue-size", driver.loc_);
}
}
\"control-socket\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
@ -1845,8 +1872,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
{JSONString} {
/* A string has been matched. It contains the actual string and single quotes.
We need to get those quotes out of the way and just use its content, e.g.

View File

@ -187,6 +187,10 @@ using namespace std;
DHCP4O6_PORT "dhcp4o6-port"
ENABLE_MULTI_THREADING "enable-multi-threading"
PACKET_THREAD_POOL_SIZE "packet-thread-pool-size"
PACKET_THREAD_QUEUE_SIZE "packet-thread-queue-size"
CONTROL_SOCKET "control-socket"
SOCKET_TYPE "socket-type"
SOCKET_NAME "socket-name"
@ -507,6 +511,9 @@ global_param: valid_lifetime
| statistic_default_sample_count
| statistic_default_sample_age
| unknown_map_entry
| enable_multi_threading
| packet_thread_pool_size
| packet_thread_queue_size
;
valid_lifetime: VALID_LIFETIME COLON INTEGER {
@ -1029,6 +1036,21 @@ flex_id: FLEX_ID {
ctx.stack_.back()->add(flex_id);
};
enable_multi_threading: ENABLE_MULTI_THREADING COLON BOOLEAN {
ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("enable-multi-threading", b);
};
packet_thread_pool_size: PACKET_THREAD_POOL_SIZE COLON INTEGER {
ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("packet-thread-pool-size", prf);
};
packet_thread_queue_size: PACKET_THREAD_QUEUE_SIZE COLON INTEGER {
ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("packet-thread-queue-size", prf);
};
hooks_libraries: HOOKS_LIBRARIES {
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("hooks-libraries", l);
@ -1995,8 +2017,6 @@ only_if_required: ONLY_IF_REQUIRED COLON BOOLEAN {
// --- end of client classes ---------------------------------
// was server-id but in is DHCPv6-only
dhcp4o6_port: DHCP4O6_PORT COLON INTEGER {
ElementPtr time(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("dhcp4o6-port", time);
@ -2277,6 +2297,8 @@ control_agent_json_object: CONTROL_AGENT {
ctx.leave();
};
// Config control information element
config_control: CONFIG_CONTROL {
ElementPtr i(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("config-control", i);
@ -2472,7 +2494,6 @@ pattern: PATTERN {
ctx.leave();
};
%%
void

View File

@ -588,6 +588,8 @@ void Dhcpv4Exchange::evaluateClasses(const Pkt4Ptr& pkt, bool depend_on_known) {
const std::string Dhcpv4Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
int Dhcpv4Srv::srv_thread_count_ = -1;
Dhcpv4Srv::Dhcpv4Srv(uint16_t server_port, uint16_t client_port,
const bool use_bcast, const bool direct_response_desired)
: io_service_(new IOService()), server_port_(server_port),
@ -937,12 +939,13 @@ Dhcpv4Srv::run_one() {
try {
bool read_pkt = true;
// Do not read more packets from socket if there are enough
// packets to be processed in the packet thread pool queue
const int max_queue_size = CfgMgr::instance().getCurrentCfg()->getServerMaxThreadQueueSize();
// Do not read more packets from socket if there are enough packets to
// be processed in the packet thread pool queue
// max_queue_size = 0 means no limit
const int max_queue_size = CfgMgr::instance().getCurrentCfg()->getPktThreadQueueSize();
const int thread_count = MultiThreadingMgr::instance().getPktThreadPoolSize();
size_t pkt_queue_size = MultiThreadingMgr::instance().getPktThreadPool().count();
if (thread_count && (pkt_queue_size >= thread_count * max_queue_size)) {
if (thread_count && max_queue_size && (pkt_queue_size >= thread_count * max_queue_size)) {
read_pkt = false;
}

View File

@ -1061,6 +1061,12 @@ protected:
CBControlDHCPv4Ptr cb_control_;
public:
/// @brief command line parameter thread count
/// when parameter is not specified, the default value is used
/// the default value is: -1 means disabled (single-threaded),
/// 0 means auto-detect, other values set thread count explicitly
static int srv_thread_count_;
/// Class methods for DHCPv4-over-DHCPv6 handler
/// @brief Updates statistics for received packets

View File

@ -10,16 +10,17 @@
#include <database/dbaccess_parser.h>
#include <database/backend_selector.h>
#include <database/server_selector.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option_definition.h>
#include <dhcp4/dhcp4_log.h>
#include <dhcp4/dhcp4_srv.h>
#include <dhcp4/json_config_parser.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option_definition.h>
#include <dhcpsrv/cb_ctl_dhcp4.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/config_backend_dhcp4_mgr.h>
#include <dhcpsrv/db_type.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/parsers/client_class_def_parser.h>
#include <dhcpsrv/parsers/dhcp_parsers.h>
#include <dhcpsrv/parsers/expiration_config_parser.h>
@ -31,7 +32,6 @@
#include <dhcpsrv/parsers/simple_parser4.h>
#include <dhcpsrv/parsers/shared_networks_list_parser.h>
#include <dhcpsrv/parsers/sanity_checks_parser.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/timer_mgr.h>
#include <process/config_ctl_parser.h>
#include <hooks/hooks_parser.h>
@ -39,21 +39,20 @@
#include <util/encode/hex.h>
#include <util/strutil.h>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <limits>
#include <iostream>
#include <iomanip>
#include <limits>
#include <map>
#include <netinet/in.h>
#include <vector>
#include <map>
using namespace std;
using namespace isc;
using namespace isc::dhcp;
using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::asiolink;
using namespace isc::hooks;
using namespace isc::process;
@ -103,6 +102,18 @@ public:
uint16_t dhcp4o6_port = getUint16(global, "dhcp4o6-port");
cfg->setDhcp4o6Port(dhcp4o6_port);
// Set enable multi threading flag.
bool enable_multi_threading = getBoolean(global, "enable-multi-threading");
cfg->setEnableMultiThreading(enable_multi_threading);
// Set packet thread pool size.
uint32_t packet_thread_pool_size = getUint32(global, "packet-thread-pool-size");
cfg->setPktThreadPoolSize(packet_thread_pool_size);
// Set packet thread queue size.
uint32_t packet_thread_queue_size = getUint32(global, "packet-thread-queue-size");
cfg->setPktThreadQueueSize(packet_thread_queue_size);
// Set the global user context.
ConstElementPtr user_context = global->get("user-context");
if (user_context) {
@ -297,7 +308,6 @@ void configureCommandChannel() {
}
}
isc::data::ConstElementPtr
configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
bool check_only) {
@ -336,13 +346,13 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
// have to be restored to global storages.
bool rollback = false;
// config_pair holds the details of the current parser when iterating over
// the parsers. It is declared outside the loops so in case of an error,
// the name of the failing parser can be retrieved in the "catch" clause.
// the parsers. It is declared outside the loop so in case of error, the
// name of the failing parser can be retrieved within the "catch" clause.
ConfigPair config_pair;
ElementPtr mutable_cfg;
SrvConfigPtr srv_cfg;
try {
// Get the staging configuration
// Get the staging configuration.
srv_cfg = CfgMgr::instance().getStagingCfg();
// This is a way to convert ConstElementPtr to ElementPtr.
@ -353,7 +363,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
// Relocate dhcp-ddns parameters that have moved to global scope.
// Rule is that a global value overrides the dhcp-ddns value, so
// we need to do this before we apply global defaults.
// Note this is done for backward compatibilty.
// Note this is done for backward compatibility.
srv_cfg->moveDdnsParams(mutable_cfg);
// Set all default values if not specified by the user.
@ -505,7 +515,6 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
}
if (config_pair.first == "shared-networks") {
/// We need to create instance of SharedNetworks4ListParser
/// and parse the list of the shared networks into the
/// CfgSharedNetworks4 object. One additional step is then to
@ -578,11 +587,13 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
(config_pair.first == "ddns-qualifying-suffix") ||
(config_pair.first == "store-extended-info") ||
(config_pair.first == "statistic-default-sample-count") ||
(config_pair.first == "statistic-default-sample-age")) {
(config_pair.first == "statistic-default-sample-age") ||
(config_pair.first == "enable-multi-threading") ||
(config_pair.first == "packet-thread-pool-size") ||
(config_pair.first == "packet-thread-queue-size")) {
CfgMgr::instance().getStagingCfg()->addConfiguredGlobal(config_pair.first,
config_pair.second);
continue;
}
// Nothing to configure for the user-context.
@ -604,7 +615,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
// defined as part of shared networks.
global_parser.sanityChecks(srv_cfg, mutable_cfg);
// Validate D2 client confuguration.
// Validate D2 client configuration.
if (!d2_client_cfg) {
d2_client_cfg.reset(new D2ClientConfig());
}
@ -655,7 +666,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
cfg = CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
CfgMgr::instance().setD2ClientConfig(cfg);
// This occurs last as if it succeeds, there is no easy way
// This occurs last as if it succeeds, there is no easy way to
// revert it. As a result, the failure to commit a subsequent
// change causes problems when trying to roll back.
const HooksConfig& libraries =
@ -665,12 +676,14 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
catch (const isc::Exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
// An error occurred, so make sure to restore the original data.
rollback = true;
} catch (...) {
// For things like bad_cast in boost::lexical_cast
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_EXCEPTION);
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
" parsing error");
// An error occurred, so make sure to restore the original data.
rollback = true;
}
}
@ -687,6 +700,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
err << "during update from config backend database: " << ex.what();
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(err.str());
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str());
// An error occurred, so make sure to restore the original data.
rollback = true;
} catch (...) {
// For things like bad_cast in boost::lexical_cast
@ -695,6 +709,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
<< "undefined configuration parsing error";
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(err.str());
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str());
// An error occurred, so make sure to restore the original data.
rollback = true;
}
}
@ -716,7 +731,5 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
return (answer);
}
int srv_thread_count = -1;
} // namespace dhcp
} // namespace isc

View File

@ -60,8 +60,6 @@ configureDhcp4Server(Dhcpv4Srv&,
isc::data::ConstElementPtr config_set,
bool check_only = false);
extern int srv_thread_count;
} // namespace dhcp
} // namespace isc

View File

@ -149,7 +149,7 @@ main(int argc, char* argv[]) {
<< "], 0-65535 allowed." << endl;
usage();
} else {
srv_thread_count = thread_count;
Dhcpv4Srv::srv_thread_count_ = thread_count;
}
break;

View File

@ -57,6 +57,7 @@ using namespace isc::hooks;
using namespace std;
namespace {
const char* PARSER_CONFIGS[] = {
// CONFIGURATION 0: one subnet with one pool, no user contexts
"{"
@ -1483,7 +1484,6 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) {
" \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }";
ConstElementPtr json1;
ASSERT_NO_THROW(json1 = parseDHCP4(config_bogus1));
ConstElementPtr json2;
@ -2763,7 +2763,6 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
EXPECT_EQ(170, def->getCode());
EXPECT_EQ(OPT_STRING_TYPE, def->getType());
EXPECT_FALSE(def->getArrayType());
}
// Goal of this test is to verify that global option data is configured
@ -3487,7 +3486,6 @@ TEST_F(Dhcp4ParserTest, optionDataMultiplePools) {
testOption(*range2.first, 23, foo2_expected, sizeof(foo2_expected));
}
// Verify that empty option name is rejected in the configuration.
TEST_F(Dhcp4ParserTest, optionNameEmpty) {
// Empty option names not allowed.
@ -3851,7 +3849,6 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
" } ]"
"}";
ASSERT_NO_THROW(json = parseDHCP4(config));
extractConfig(config);
@ -4009,7 +4006,6 @@ TEST_F(Dhcp4ParserTest, vendorOptionsCsv) {
ASSERT_FALSE(desc2.option_);
}
// Tests of the hooks libraries configuration. All tests have the pre-
// condition (checked in the test fixture's SetUp() method) that no hooks
// libraries are loaded at the start of the tests.
@ -4080,7 +4076,6 @@ buildHooksLibrariesConfig(const char* library1 = NULL,
return (buildHooksLibrariesConfig(libraries));
}
// The goal of this test is to verify the configuration of hooks libraries if
// none are specified.
TEST_F(Dhcp4ParserTest, NoHooksLibraries) {
@ -4617,7 +4612,6 @@ TEST_F(Dhcp4ParserTest, subnetRelayInfoList) {
EXPECT_TRUE(subnet->hasRelayAddress(IOAddress("192.0.3.124")));
}
// Goal of this test is to verify that multiple subnets can be configured
// with defined client classes.
TEST_F(Dhcp4ParserTest, classifySubnets) {
@ -4964,7 +4958,6 @@ TEST_F(Dhcp4ParserTest, reservations) {
EXPECT_FALSE(hosts_cfg->get4(234, Host::IDENT_CIRCUIT_ID,
&circuit_id[0], circuit_id.size()));
// Repeat the test for the DUID based reservation in this subnet.
std::vector<uint8_t> duid_r(duid.rbegin(), duid.rend());
host = hosts_cfg->get4(542, Host::IDENT_DUID, &duid_r[0], duid_r.size());
@ -5321,6 +5314,41 @@ TEST_F(Dhcp4ParserTest, hostReservationGlobal) {
EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode());
}
/// Check that the multi-threading settings have a default value when not
/// specified.
TEST_F(Dhcp4ParserTest, multiThreadingDefaultSettings) {
ConstElementPtr status;
string config = "{ " + genIfaceConfig() + "," +
"\"subnet4\": [ ]"
"}";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP4(config));
extractConfig(config);
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
// returned value should be 0 (success)
checkResult(status, 0);
// The value of enable-multi-threading must be equal to the default value
// (false). The default value is defined in GLOBAL4_DEFAULTS in
// simple_parser4.cc.
EXPECT_EQ(false,
CfgMgr::instance().getStagingCfg()->getEnableMultiThreading());
// The value of packet-thread-pool-size must be equal to the default value
// (0). The default value is defined in GLOBAL4_DEFAULTS in
// simple_parser4.cc.
EXPECT_EQ(0, CfgMgr::instance().getStagingCfg()->getPktThreadPoolSize());
// The value of packet-thread-queue-size must be equal to the default value
// (4). The default value is defined in GLOBAL4_DEFAULTS in
// simple_parser4.cc.
EXPECT_EQ(4, CfgMgr::instance().getStagingCfg()->getPktThreadQueueSize());
}
/// Check that the decline-probation-period has a default value when not
/// specified.
TEST_F(Dhcp4ParserTest, declineTimerDefault) {
@ -5340,8 +5368,8 @@ TEST_F(Dhcp4ParserTest, declineTimerDefault) {
checkResult(status, 0);
// The value of decline-probation-period must be equal to the
// default value (86400). The default value is defined in GLOBAL6_DEFAULTS in
// simple_parser6.cc.
// default value (86400). The default value is defined in GLOBAL4_DEFAULTS in
// simple_parser4.cc.
EXPECT_EQ(86400, CfgMgr::instance().getStagingCfg()->getDeclinePeriod());
}
@ -5368,7 +5396,6 @@ TEST_F(Dhcp4ParserTest, dhcp4o6portDefault) {
EXPECT_EQ(0, CfgMgr::instance().getStagingCfg()->getDhcp4o6Port());
}
/// Check that the decline-probation-period value can be set properly.
TEST_F(Dhcp4ParserTest, declineTimer) {
ConstElementPtr status;
@ -5489,7 +5516,6 @@ TEST_F(Dhcp4ParserTest, expiredLeasesProcessingError) {
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
}
// Checks if the DHCPv4 is able to parse the configuration without 4o6 parameters
// and does not set 4o6 fields at all.
TEST_F(Dhcp4ParserTest, 4o6default) {
@ -5620,7 +5646,6 @@ TEST_F(Dhcp4ParserTest, 4o6subnetBogus) {
checkResult(status, 1);
}
// Checks if the DHCPv4 is able to parse the configuration with 4o6 network
// interface defined.
TEST_F(Dhcp4ParserTest, 4o6iface) {
@ -5763,7 +5788,6 @@ TEST_F(Dhcp4ParserTest, validClientClassDictionary) {
" } ] \n"
"} \n";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP4(config));
extractConfig(config);
@ -6217,7 +6241,6 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
" \"pools\": [ { \"pool\": \"192.0.3.1-192.0.3.10\" } ]\n"
" }\n"
" ]\n"
" } ]\n"
"} \n";
@ -6900,8 +6923,10 @@ TEST_F(Dhcp4ParserTest, dhcpQueueControl) {
// Fetch the queue control info.
staged_control = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
// Make sure the staged queue config exists.
ASSERT_TRUE(staged_control);
// Now build the expected queue control content.
if (scenario.json_.empty()) {
exp_control = Element::createMap();
@ -7169,5 +7194,35 @@ TEST_F(Dhcp4ParserTest, statsDefaultLimits) {
EXPECT_EQ("00:00:05",
util::durationToText(stats_mgr.getMaxSampleAgeDefault(), 0));
}
/// Check that the multi threading settings can be set properly.
TEST_F(Dhcp4ParserTest, multiThreadingSettings) {
ConstElementPtr status;
string config = "{ " + genIfaceConfig() + "," +
"\"enable-multi-threading\": true,"
"\"packet-thread-pool-size\": 256,"
"\"packet-thread-queue-size\": 256,"
"\"subnet4\": [ ]"
"}";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP4(config));
extractConfig(config);
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
// returned value should be 0 (success)
checkResult(status, 0);
// The value of multi-threading settings must be equal to the specified
// values
EXPECT_EQ(true,
CfgMgr::instance().getStagingCfg()->getEnableMultiThreading());
EXPECT_EQ(256,
CfgMgr::instance().getStagingCfg()->getPktThreadPoolSize());
EXPECT_EQ(256,
CfgMgr::instance().getStagingCfg()->getPktThreadQueueSize());
}
}

View File

@ -140,17 +140,20 @@ ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
"processCommand(\"config-set\", json)");
}
// command line parameters overwrite file and database configuration
bool enabled = false;
if (srv_thread_count >= 0) {
if (Dhcpv6Srv::srv_thread_count_ >= 0) {
enabled = true;
}
if (enabled) {
CfgMgr::instance().getCurrentCfg()->setServerThreadCount(srv_thread_count);
CfgMgr::instance().getCurrentCfg()->setServerMaxThreadQueueSize(4);
CfgMgr::instance().getCurrentCfg()->setPktThreadPoolSize(Dhcpv6Srv::srv_thread_count_);
CfgMgr::instance().getCurrentCfg()->setPktThreadQueueSize(0);
LOG_FATAL(dhcp6_logger, DHCP6_MULTI_THREADING_WARNING);
} else {
enabled = CfgMgr::instance().getCurrentCfg()->getEnableMultiThreading();
}
MultiThreadingMgr::instance().apply(enabled,
CfgMgr::instance().getCurrentCfg()->getServerThreadCount());
CfgMgr::instance().getCurrentCfg()->getPktThreadPoolSize());
// Now check is the returned result is successful (rcode=0) or not
// (see @ref isc::config::parseAnswer).
@ -175,7 +178,7 @@ ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
LOG_WARN(dhcp6_logger, DHCP6_MULTI_THREADING_INFO)
.arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
.arg(MultiThreadingMgr::instance().getPktThreadPoolSize())
.arg(CfgMgr::instance().getCurrentCfg()->getServerMaxThreadQueueSize());
.arg(CfgMgr::instance().getCurrentCfg()->getPktThreadQueueSize());
return (result);
}

View File

@ -1647,7 +1647,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"parameters\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::HOOKS_LIBRARIES:
@ -1810,6 +1809,33 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"enable-multi-threading\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
return isc::dhcp::Dhcp6Parser::make_ENABLE_MULTI_THREADING(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("enable-multi-threading", driver.loc_);
}
}
\"packet-thread-pool-size\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
return isc::dhcp::Dhcp6Parser::make_PACKET_THREAD_POOL_SIZE(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("packet-thread-pool-size", driver.loc_);
}
}
\"packet-thread-queue-size\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
return isc::dhcp::Dhcp6Parser::make_PACKET_THREAD_QUEUE_SIZE(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("packet-thread-queue-size", driver.loc_);
}
}
\"control-socket\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
@ -1909,7 +1935,6 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
{JSONString} {
/* A string has been matched. It contains the actual string and single quotes.
We need to get those quotes out of the way and just use its content, e.g.

View File

@ -50,6 +50,7 @@ using namespace std;
NULL_TYPE "null"
DHCP6 "Dhcp6"
DATA_DIRECTORY "data-directory"
CONFIG_CONTROL "config-control"
CONFIG_DATABASES "config-databases"
@ -191,6 +192,10 @@ using namespace std;
DHCP4O6_PORT "dhcp4o6-port"
ENABLE_MULTI_THREADING "enable-multi-threading"
PACKET_THREAD_POOL_SIZE "packet-thread-pool-size"
PACKET_THREAD_QUEUE_SIZE "packet-thread-queue-size"
CONTROL_SOCKET "control-socket"
SOCKET_TYPE "socket-type"
SOCKET_NAME "socket-name"
@ -417,7 +422,8 @@ syntax_map: LCURLY_BRACKET {
ctx.require("Dhcp6", ctx.loc2pos(@1), ctx.loc2pos(@4));
};
// This represents top-level entries: Dhcp6, Dhcp4, DhcpDdns, Logging
// This represents top-level entries: Control-agent, Dhcp6, Dhcp4,
// DhcpDdns, Logging
global_objects: global_object
| global_objects COMMA global_object
;
@ -513,6 +519,9 @@ global_param: data_directory
| statistic_default_sample_count
| statistic_default_sample_age
| unknown_map_entry
| enable_multi_threading
| packet_thread_pool_size
| packet_thread_queue_size
;
data_directory: DATA_DIRECTORY {
@ -725,7 +734,6 @@ re_detect: RE_DETECT COLON BOOLEAN {
ctx.stack_.back()->set("re-detect", b);
};
lease_database: LEASE_DATABASE {
ElementPtr i(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("lease-database", i);
@ -1039,6 +1047,21 @@ relay_supplied_options: RELAY_SUPPLIED_OPTIONS {
ctx.leave();
};
enable_multi_threading: ENABLE_MULTI_THREADING COLON BOOLEAN {
ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("enable-multi-threading", b);
};
packet_thread_pool_size: PACKET_THREAD_POOL_SIZE COLON INTEGER {
ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("packet-thread-pool-size", prf);
};
packet_thread_queue_size: PACKET_THREAD_QUEUE_SIZE COLON INTEGER {
ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("packet-thread-queue-size", prf);
};
hooks_libraries: HOOKS_LIBRARIES {
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("hooks-libraries", l);
@ -1328,7 +1351,6 @@ rapid_commit: RAPID_COMMIT COLON BOOLEAN {
ctx.stack_.back()->set("rapid-commit", rc);
};
// ---- shared-networks ---------------------
shared_networks: SHARED_NETWORKS {
@ -1670,6 +1692,7 @@ sub_pool6: LCURLY_BRACKET {
} pool_params RCURLY_BRACKET {
// The pool parameter is required.
ctx.require("pool", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
pool_params: pool_param
@ -2158,6 +2181,7 @@ socket_name: SOCKET_NAME {
ctx.leave();
};
// --- dhcp-queue-control ---------------------------------------------
dhcp_queue_control: DHCP_QUEUE_CONTROL {
@ -2368,6 +2392,7 @@ dep_hostname_char_replacement: HOSTNAME_CHAR_REPLACEMENT {
ctx.leave();
};
// JSON entries for Dhcp4 and DhcpDdns
dhcp4_json_object: DHCP4 {

View File

@ -204,6 +204,8 @@ namespace dhcp {
const std::string Dhcpv6Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
int Dhcpv6Srv::srv_thread_count_ = -1;
Dhcpv6Srv::Dhcpv6Srv(uint16_t server_port, uint16_t client_port)
: io_service_(new IOService()), server_port_(server_port),
client_port_(client_port), serverid_(), shutdown_(true),
@ -523,12 +525,13 @@ void Dhcpv6Srv::run_one() {
try {
bool read_pkt = true;
// Do not read more packets from socket if there are enough
// packets to be processed in the packet thread pool queue
const int max_queue_size = CfgMgr::instance().getCurrentCfg()->getServerMaxThreadQueueSize();
// Do not read more packets from socket if there are enough packets to
// be processed in the packet thread pool queue
// max_queue_size = 0 means no limit
const int max_queue_size = CfgMgr::instance().getCurrentCfg()->getPktThreadQueueSize();
const int thread_count = MultiThreadingMgr::instance().getPktThreadPoolSize();
size_t pkt_queue_size = MultiThreadingMgr::instance().getPktThreadPool().count();
if (thread_count && (pkt_queue_size >= thread_count * max_queue_size)) {
if (thread_count && max_queue_size && (pkt_queue_size >= thread_count * max_queue_size)) {
read_pkt = false;
}

View File

@ -1061,6 +1061,12 @@ protected:
uint16_t client_port_;
public:
/// @brief command line parameter thread count
/// when parameter is not specified, the default value is used
/// the default value is: -1 means disabled (single-threaded),
/// 0 means auto-detect, other values set thread count explicitly
static int srv_thread_count_;
/// @note used by DHCPv4-over-DHCPv6 so must be public and static
/// @brief Updates statistics for transmitted packets

View File

@ -11,11 +11,11 @@
#include <cc/command_interpreter.h>
#include <config/command_mgr.h>
#include <database/dbaccess_parser.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/libdhcp++.h>
#include <dhcp6/json_config_parser.h>
#include <dhcp6/dhcp6_log.h>
#include <dhcp6/dhcp6_srv.h>
#include <dhcp/iface_mgr.h>
#include <dhcp6/json_config_parser.h>
#include <dhcpsrv/cb_ctl_dhcp4.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/cfgmgr.h>
@ -40,14 +40,13 @@
#include <hooks/hooks_parser.h>
#include <log/logger_support.h>
#include <process/config_ctl_parser.h>
#include <util/encode/hex.h>
#include <util/strutil.h>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <limits>
@ -55,14 +54,15 @@
#include <netinet/in.h>
#include <vector>
#include <stdint.h>
using namespace std;
using namespace isc;
using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::asiolink;
using namespace isc::hooks;
using namespace isc::process;
using namespace isc::config;
using namespace isc::db;
namespace {
@ -188,6 +188,18 @@ public:
uint16_t dhcp4o6_port = getUint16(global, "dhcp4o6-port");
srv_config->setDhcp4o6Port(dhcp4o6_port);
// Set enable multi threading flag.
bool enable_multi_threading = getBoolean(global, "enable-multi-threading");
srv_config->setEnableMultiThreading(enable_multi_threading);
// Set packet thread pool size.
uint32_t packet_thread_pool_size = getUint32(global, "packet-thread-pool-size");
srv_config->setPktThreadPoolSize(packet_thread_pool_size);
// Set packet thread queue size.
uint32_t packet_thread_queue_size = getUint32(global, "packet-thread-queue-size");
srv_config->setPktThreadQueueSize(packet_thread_queue_size);
// Set the global user context.
ConstElementPtr user_context = global->get("user-context");
if (user_context) {
@ -311,7 +323,6 @@ public:
}
}
if (iface.empty()) {
iface = (*subnet)->getIface();
continue;
@ -349,8 +360,6 @@ public:
}
}
};
} // anonymous namespace
@ -627,12 +636,11 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
}
if (config_pair.first == "shared-networks") {
/// We need to create instance of SharedNetworks4ListParser
/// We need to create instance of SharedNetworks6ListParser
/// and parse the list of the shared networks into the
/// CfgSharedNetworks4 object. One additional step is then to
/// CfgSharedNetworks6 object. One additional step is then to
/// add subnets from the CfgSharedNetworks6 into CfgSubnets6
/// as well.
SharedNetworks6ListParser parser;
CfgSharedNetworks6Ptr cfg = srv_config->getCfgSharedNetworks6();
parser.parse(cfg, config_pair.second);
@ -697,7 +705,10 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
(config_pair.first == "ddns-qualifying-suffix") ||
(config_pair.first == "store-extended-info") ||
(config_pair.first == "statistic-default-sample-count") ||
(config_pair.first == "statistic-default-sample-age")) {
(config_pair.first == "statistic-default-sample-age") ||
(config_pair.first == "enable-multi-threading") ||
(config_pair.first == "packet-thread-pool-size") ||
(config_pair.first == "packet-thread-queue-size")) {
CfgMgr::instance().getStagingCfg()->addConfiguredGlobal(config_pair.first,
config_pair.second);
continue;
@ -728,7 +739,7 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
// defined as part of shared networks.
global_parser.sanityChecks(srv_config, mutable_cfg);
// Validate D2 client confuguration.
// Validate D2 client configuration.
if (!d2_client_cfg) {
d2_client_cfg.reset(new D2ClientConfig());
}
@ -844,7 +855,5 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
return (answer);
}
int srv_thread_count = -1;
} // namespace dhcp
} // namespace isc

View File

@ -44,8 +44,6 @@ isc::data::ConstElementPtr
configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
bool check_only = false);
extern int srv_thread_count;
} // namespace dhcp
} // namespace isc

View File

@ -149,7 +149,7 @@ main(int argc, char* argv[]) {
<< "], 0-65535 allowed." << endl;
usage();
} else {
srv_thread_count = thread_count;
Dhcpv6Srv::srv_thread_count_ = thread_count;
}
break;

View File

@ -510,8 +510,8 @@ public:
/// @brief Create the simple configuration with single option.
///
/// This function allows to set one of the parameters that configure
/// option value. These parameters are: "name", "code", "data" and
/// "csv-format".
/// option value. These parameters are: "name", "code", "data",
/// "csv-format" and "space".
///
/// @param param_value string holding option parameter value to be
/// injected into the configuration string.
@ -784,7 +784,6 @@ public:
return (ReturnType());
}
/// @brief Test invalid option parameter value.
///
/// This test function constructs the simple configuration
@ -1203,7 +1202,6 @@ TEST_F(Dhcp6ParserTest, emptySubnet) {
ConstElementPtr status;
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
// returned value should be 0 (success)
checkResult(status, 0);
}
@ -1311,7 +1309,7 @@ TEST_F(Dhcp6ParserTest, multipleSubnets) {
} while (++cnt < 10);
}
// This checks that it is possible to assign arbitrary ids for subnets.
// This test checks that it is possible to assign arbitrary ids for subnets.
TEST_F(Dhcp6ParserTest, multipleSubnetsExplicitIDs) {
ConstElementPtr x;
// Four subnets with arbitrary subnet ids.
@ -1407,7 +1405,6 @@ TEST_F(Dhcp6ParserTest, multipleSubnetsOverlappingIDs) {
EXPECT_TRUE(errorContainsPosition(x, "<string>"));
}
// Goal of this test is to verify that a previously configured subnet can be
// deleted in subsequent reconfiguration.
TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) {
@ -1541,8 +1538,6 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) {
EXPECT_EQ(4, subnets->at(2)->getID());
}
// This test checks if it is possible to override global values
// on a per subnet basis.
TEST_F(Dhcp6ParserTest, subnetLocal) {
@ -1658,7 +1653,6 @@ TEST_F(Dhcp6ParserTest, subnetInterfaceBogus) {
EXPECT_FALSE(subnet);
}
// This test checks if it is not allowed to define global interface
// parameter.
TEST_F(Dhcp6ParserTest, interfaceGlobal) {
@ -1686,7 +1680,6 @@ TEST_F(Dhcp6ParserTest, interfaceGlobal) {
EXPECT_THROW(parseDHCP6(config), Dhcp6ParseError);
}
// This test checks if it is possible to define a subnet with an
// interface-id option defined.
TEST_F(Dhcp6ParserTest, subnetInterfaceId) {
@ -1734,7 +1727,6 @@ TEST_F(Dhcp6ParserTest, subnetInterfaceId) {
EXPECT_TRUE(selector.interface_id_->equals(subnet->getInterfaceId()));
}
// This test checks if it is not allowed to define global interface
// parameter.
TEST_F(Dhcp6ParserTest, interfaceIdGlobal) {
@ -1958,7 +1950,6 @@ TEST_F(Dhcp6ParserTest, multiplePools) {
EXPECT_TRUE(subnets->at(0)->getPools(Lease::TYPE_PD).empty());
}
// Test verifies that a subnet with pool values that do not belong to that
// pool are rejected.
TEST_F(Dhcp6ParserTest, poolOutOfSubnet) {
@ -1972,7 +1963,6 @@ TEST_F(Dhcp6ParserTest, poolOutOfSubnet) {
" \"subnet\": \"2001:db8:1::/64\" } ],"
"\"valid-lifetime\": 4000 }";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP6(config));
@ -2409,7 +2399,6 @@ TEST_F(Dhcp6ParserTest, subnetAndPrefixDelegated) {
EXPECT_EQ(lastAddrInPrefix(prefixAddress, 64), p6->getLastAddress());
}
// Goal of this test is check for proper handling of invalid prefix delegation
// pool configuration. It uses an array of invalid configurations to check
// a variety of configuration errors.
@ -2903,7 +2892,6 @@ TEST_F(Dhcp6ParserTest, optionIntegerTypes) {
checkResult(status, 0);
}
/// The goal of this test is to verify that the invalid encapsulated
/// option space name is not accepted.
TEST_F(Dhcp6ParserTest, optionDefInvalidEncapsulatedSpace) {
@ -3640,7 +3628,6 @@ TEST_F(Dhcp6ParserTest, optionDataMultiplePools) {
testOption(*range3.first, D6O_SUBSCRIBER_ID, subscriber_id_expected2,
sizeof(subscriber_id_expected2));
pool = subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8:1::300"));
ASSERT_TRUE(pool);
pool6 = boost::dynamic_pointer_cast<Pool6>(pool);
@ -3957,7 +3944,6 @@ TEST_F(Dhcp6ParserTest, rdnssOption) {
EXPECT_EQ("example.com.", optionCustom->readFqdn(4));
}
// This test checks if vendor options can be specified in the config file
// (in hex format), and later retrieved from configured subnet
TEST_F(Dhcp6ParserTest, vendorOptionsHex) {
@ -4224,7 +4210,6 @@ TEST_F(Dhcp6ParserTest, DISABLED_stdOptionDataEncapsulate) {
// condition (checked in the test fixture's SetUp() method) that no hooks
// libraries are loaded at the start of the tests.
// Helper function to return a configuration containing an arbitrary number
// of hooks libraries.
std::string
@ -4294,7 +4279,6 @@ buildHooksLibrariesConfig(const char* library1 = NULL,
return (buildHooksLibrariesConfig(libraries));
}
// The goal of this test is to verify the configuration of hooks libraries if
// none are specified.
TEST_F(Dhcp6ParserTest, NoHooksLibraries) {
@ -4364,7 +4348,6 @@ TEST_F(Dhcp6ParserTest, LibrariesSpecified) {
}
// This test verifies that it is possible to select subset of interfaces on
// which server should listen.
TEST_F(Dhcp6ParserTest, selectedInterfaces) {
@ -4382,7 +4365,6 @@ TEST_F(Dhcp6ParserTest, selectedInterfaces) {
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000 }";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP6(config));
extractConfig(config);
@ -4421,7 +4403,6 @@ TEST_F(Dhcp6ParserTest, allInterfaces) {
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000 }";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP6(config));
extractConfig(config);
@ -4437,7 +4418,6 @@ TEST_F(Dhcp6ParserTest, allInterfaces) {
EXPECT_TRUE(test_config.socketOpen("eth1", AF_INET6));
}
// This test checks if it is possible to specify relay information
TEST_F(Dhcp6ParserTest, subnetRelayInfo) {
@ -5233,7 +5213,6 @@ TEST_F(Dhcp6ParserTest, reservations) {
ASSERT_TRUE(opt_prf);
EXPECT_EQ(11, static_cast<int>(opt_prf->getValue()));
// The HW address used for one of the reservations in the subnet 542
// consists of numbers from 6 to 1. So, let's just reverse the order
// of the address from the previous test.
@ -5532,7 +5511,6 @@ TEST_F(Dhcp6ParserTest, macSources2) {
EXPECT_EQ(HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID, sources[2]);
}
/// The goal of this test is to verify that empty MAC sources configuration
/// is rejected. If specified, this has to have at least one value.
TEST_F(Dhcp6ParserTest, macSourcesEmpty) {
@ -5911,6 +5889,41 @@ TEST_F(Dhcp6ParserTest, testDataDir) {
EXPECT_NE(original_datadir, string(CfgMgr::instance().getDataDir()));
}
/// Check that the multi-threading settings have a default value when not
/// specified.
TEST_F(Dhcp6ParserTest, multiThreadingDefaultSettings) {
ConstElementPtr status;
string config = "{ " + genIfaceConfig() + "," +
"\"subnet6\": [ ]"
"}";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP6(config));
extractConfig(config);
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
// returned value should be 0 (success)
checkResult(status, 0);
// The value of enable-multi-threading must be equal to the default value
// (false). The default value is defined in GLOBAL6_DEFAULTS in
// simple_parser6.cc.
EXPECT_EQ(false,
CfgMgr::instance().getStagingCfg()->getEnableMultiThreading());
// The value of packet-thread-pool-size must be equal to the default value
// (0). The default value is defined in GLOBAL6_DEFAULTS in
// simple_parser6.cc.
EXPECT_EQ(0, CfgMgr::instance().getStagingCfg()->getPktThreadPoolSize());
// The value of packet-thread-queue-size must be equal to the default value
// (4). The default value is defined in GLOBAL6_DEFAULTS in
// simple_parser6.cc.
EXPECT_EQ(4, CfgMgr::instance().getStagingCfg()->getPktThreadQueueSize());
}
/// Check that the decline-probation-period value has a default value if not
/// specified explicitly.
TEST_F(Dhcp6ParserTest, declineTimerDefault) {
@ -6077,7 +6090,6 @@ TEST_F(Dhcp6ParserTest, expiredLeasesProcessingError) {
// Verifies that simple list of valid classes parses and
// is staged for commit.
TEST_F(Dhcp6ParserTest, validClientClassDictionary) {
string config = "{ " + genIfaceConfig() + ","
"\"preferred-lifetime\": 3000, \n"
"\"rebind-timer\": 2000, \n"
@ -6826,7 +6838,6 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDeriveInterfaces) {
EXPECT_EQ("", s->getIface().get());
}
// It is not allowed to have different values for interfaces names is subnets
// in the same shared network.
TEST_F(Dhcp6ParserTest, sharedNetworksInterfacesMixed) {
@ -6894,7 +6905,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDeriveClientClass) {
CfgSharedNetworks6Ptr cfg_net = CfgMgr::instance().getStagingCfg()
->getCfgSharedNetworks6();
// Two shared networks are expeced.
// Two shared networks are expected.
ASSERT_TRUE(cfg_net);
const SharedNetwork6Collection* nets = cfg_net->getAll();
ASSERT_TRUE(nets);
@ -7118,7 +7129,7 @@ TEST_F(Dhcp6ParserTest, comments) {
ASSERT_TRUE(ctx_opt_desc->get("comment"));
EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
// And there there are some client classes.
// And there are some client classes.
const ClientClassDictionaryPtr& dict =
CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
ASSERT_TRUE(dict);
@ -7428,6 +7439,7 @@ TEST_F(Dhcp6ParserTest, configControlInfo) {
registerBackendType(ConfigBackendDHCPv6Mgr::instance(),
"mysql"));
// Should parse ok, now that the factory has been registered.
configure(config, CONTROL_RESULT_SUCCESS, "");
// Make sure the config control info is there.
@ -7454,7 +7466,6 @@ TEST_F(Dhcp6ParserTest, configControlInfo) {
// Check whether it is possible to configure server-tag
TEST_F(Dhcp6ParserTest, serverTag) {
// Config without server-tag
string config_no_tag = "{ " + genIfaceConfig() + "," +
"\"subnet6\": [ ] "
@ -7617,7 +7628,7 @@ TEST_F(Dhcp6ParserTest, dhcpQueueControlInvalid) {
"expecting boolean"
},
{
"queue type not a string",
"queue enabled, type not a string",
"{ \n"
" \"enable-queue\": true, \n"
" \"queue-type\": 7777 \n"
@ -7752,5 +7763,34 @@ TEST_F(Dhcp6ParserTest, statsDefaultLimits) {
util::durationToText(stats_mgr.getMaxSampleAgeDefault(), 0));
}
/// Check that the multi threading settings can be set properly.
TEST_F(Dhcp6ParserTest, multiThreadingSettings) {
ConstElementPtr status;
string config = "{ " + genIfaceConfig() + "," +
"\"enable-multi-threading\": true,"
"\"packet-thread-pool-size\": 256,"
"\"packet-thread-queue-size\": 256,"
"\"subnet6\": [ ]"
"}";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP6(config));
extractConfig(config);
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
// returned value should be 0 (success)
checkResult(status, 0);
// The value of multi-threading settings must be equal to the specified
// values
EXPECT_EQ(true,
CfgMgr::instance().getStagingCfg()->getEnableMultiThreading());
EXPECT_EQ(256,
CfgMgr::instance().getStagingCfg()->getPktThreadPoolSize());
EXPECT_EQ(256,
CfgMgr::instance().getStagingCfg()->getPktThreadQueueSize());
}
}

View File

@ -85,7 +85,10 @@ const SimpleKeywords SimpleParser4::GLOBAL4_PARAMETERS = {
{ "ddns-qualifying-suffix", Element::string },
{ "store-extended-info", Element::boolean },
{ "statistic-default-sample-count", Element::integer },
{ "statistic-default-sample-age", Element::integer }
{ "statistic-default-sample-age", Element::integer },
{ "enable-multi-threading", Element::boolean },
{ "packet-thread-pool-size", Element::integer },
{ "packet-thread-queue-size", Element::integer }
};
/// @brief This table defines default global values for DHCPv4
@ -118,7 +121,10 @@ const SimpleDefaults SimpleParser4::GLOBAL4_DEFAULTS = {
{ "hostname-char-replacement", Element::string, "" },
{ "store-extended-info", Element::boolean, "false" },
{ "statistic-default-sample-count", Element::integer, "20" },
{ "statistic-default-sample-age", Element::integer, "0" }
{ "statistic-default-sample-age", Element::integer, "0" },
{ "enable-multi-threading", Element::boolean, "false" },
{ "packet-thread-pool-size", Element::integer, "0" },
{ "packet-thread-queue-size", Element::integer, "4" }
};
/// @brief This table defines all option definition parameters.
@ -474,5 +480,5 @@ size_t SimpleParser4::deriveParameters(ElementPtr global) {
return (cnt);
}
};
};
} // namespace dhcp
} // namespace isc

View File

@ -85,7 +85,10 @@ const SimpleKeywords SimpleParser6::GLOBAL6_PARAMETERS = {
{ "ddns-qualifying-suffix", Element::string },
{ "store-extended-info", Element::boolean },
{ "statistic-default-sample-count", Element::integer },
{ "statistic-default-sample-age", Element::integer }
{ "statistic-default-sample-age", Element::integer },
{ "enable-multi-threading", Element::boolean },
{ "packet-thread-pool-size", Element::integer },
{ "packet-thread-queue-size", Element::integer }
};
/// @brief This table defines default global values for DHCPv6
@ -113,7 +116,10 @@ const SimpleDefaults SimpleParser6::GLOBAL6_DEFAULTS = {
{ "hostname-char-replacement", Element::string, "" },
{ "store-extended-info", Element::boolean, "false" },
{ "statistic-default-sample-count", Element::integer, "20" },
{ "statistic-default-sample-age", Element::integer, "0" }
{ "statistic-default-sample-age", Element::integer, "0" },
{ "enable-multi-threading", Element::boolean, "false" },
{ "packet-thread-pool-size", Element::integer, "0" },
{ "packet-thread-queue-size", Element::integer, "4" }
};
/// @brief This table defines all option definition parameters.
@ -476,5 +482,5 @@ size_t SimpleParser6::deriveParameters(ElementPtr global) {
return (cnt);
}
};
};
} // namespace dhcp
} // namespace isc

View File

@ -42,8 +42,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),
enable_multi_threading_(false),
pkt_thread_pool_size_(0), pkt_thread_queue_size_(0),
d2_client_config_(new D2ClientConfig()),
configured_globals_(Element::createMap()),
cfg_consist_(new CfgConsistency()) {
@ -62,8 +62,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),
enable_multi_threading_(false),
pkt_thread_pool_size_(0), pkt_thread_queue_size_(0),
d2_client_config_(new D2ClientConfig()),
configured_globals_(Element::createMap()),
cfg_consist_(new CfgConsistency()) {

View File

@ -705,32 +705,46 @@ public:
return (dhcp4o6_port_);
}
/// @brief Sets the server thread count.
/// @brief Sets the enable multi threading flag.
///
/// @param threads value of the server thread count
void setServerThreadCount(uint32_t threads) {
server_threads_ = threads;
/// @param size value of the enable multi threading flag
void setEnableMultiThreading(bool enabled) {
enable_multi_threading_ = enabled;
}
/// @brief Retrieves the server thread count.
/// @brief Retrieves the enable multi threading flag.
///
/// @return value of the server thread count
uint32_t getServerThreadCount() const {
return (server_threads_);
/// @return value of the enable multi threading flag
uint32_t getEnableMultiThreading() const {
return (enable_multi_threading_);
}
/// @brief Sets the server max thread queue size.
/// @brief Sets the packet thread pool size.
///
/// @param size max thread queue size
void setServerMaxThreadQueueSize(uint32_t size) {
server_max_thread_queue_size_ = size;
/// @param size value of the packet thread pool size
void setPktThreadPoolSize(uint32_t size) {
pkt_thread_pool_size_ = size;
}
/// @brief Retrieves the server max thread queue size.
/// @brief Retrieves the packet thread pool size.
///
/// @return value of the max thread queue size
uint32_t getServerMaxThreadQueueSize() const {
return (server_max_thread_queue_size_);
/// @return value of the packet thread pool size
uint32_t getPktThreadPoolSize() const {
return (pkt_thread_pool_size_);
}
/// @brief Sets the packet thread queue size.
///
/// @param size value of the packet thread queue size
void setPktThreadQueueSize(uint32_t size) {
pkt_thread_queue_size_ = size;
}
/// @brief Retrieves the packet thread queue size.
///
/// @return value of the packet thread queue size
uint32_t getPktThreadQueueSize() const {
return (pkt_thread_queue_size_);
}
/// @brief Returns pointer to the D2 client configuration
@ -951,11 +965,14 @@ 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 enable multi threading flag.
bool enable_multi_threading_;
/// @brief The server max thread queue size.
uint32_t server_max_thread_queue_size_;
/// @brief The packet thread pool size.
uint32_t pkt_thread_pool_size_;
/// @brief The packet thread queue size.
uint32_t pkt_thread_queue_size_;
/// @brief Stores D2 client configuration
D2ClientConfigPtr d2_client_config_;