Commit 32d8549e authored by Thomas Markwalder's avatar Thomas Markwalder

[#42] kea-dhcp6 can now parse and use queue-control

src/bin/dhcp6/ctrl_dhcp6_srv.cc
    ControlledDhcpv6Srv::processConfig() - adde packet queue config logic

src/bin/dhcp6/dhcp6_lexer.ll
    Added parsing of queue-control

src/bin/dhcp6/dhcp6_messages.mes
    Added DHCP6_CONFIG_PACKET_QUEUE message

src/bin/dhcp6/dhcp6_parser.yy

src/bin/dhcp6/json_config_parser.cc
    configureDhcp6Server() - now parses "queue-control"

src/bin/dhcp6/parser_context.*
    Added QUEUE_CONTROL

src/bin/dhcp6/tests/config_parser_unittest.cc
    TEST_F(Dhcp6ParserTest, queueControl)
    TEST_F(Dhcp6ParserTest, queueControlInvalid) - new tests

src/lib/dhcpsrv/parsers/queue_control_parser.*
    Revamped to construct an ElementPtr rather than QueueControl
parent 4dc3ba6b
......@@ -653,6 +653,31 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
return (isc::config::createAnswer(1, err.str()));
}
// Configure packet queue
try {
data::ConstElementPtr qc;
qc = CfgMgr::instance().getStagingCfg()->getQueueControlInfo();
if (!qc) {
// @todo For now we're manually constructing default queue config
// This probably needs to be built into the PQM?
data::ElementPtr default_qc = data::Element::createMap();
default_qc->set("queue-type", data::Element::create("kea-ring6"));
default_qc->set("capacity", data::Element::create(static_cast<long int>(500)));
PacketQueueMgr6::instance().createPacketQueue(default_qc);
} else {
PacketQueueMgr6::instance().createPacketQueue(qc);
}
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CONFIG_PACKET_QUEUE)
.arg(PacketQueueMgr6::instance().getPacketQueue()->getInfoStr());
} catch (const std::exception& ex) {
std::ostringstream err;
err << "Error setting packet queue controls after server reconfiguration: "
<< ex.what();
return (isc::config::createAnswer(1, err.str()));
}
// Configuration may change active interfaces. Therefore, we have to reopen
// sockets according to new configuration. It is possible that this
// operation will fail for some interfaces but the openSockets function
......
This diff is collapsed.
......@@ -1597,6 +1597,15 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"queue-control\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
return isc::dhcp::Dhcp6Parser::make_QUEUE_CONTROL(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("queue-control", driver.loc_);
}
}
\"dhcp-ddns\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
......
......@@ -90,6 +90,11 @@ If this is an initial configuration (during server's startup) the server
will fail to start. If this is a dynamic reconfiguration attempt the
server will continue to use an old configuration.
% DHCP6_CONFIG_PACKET_QUEUE DHCPv6 packet queue info after configuration: %1
This debug message is emitted during DHCPv6 server configuration, immediately
after configuring the DHCPv6 packet queue. The information shown depends
upon the packet queue type selected.
% DHCP6_CONFIG_RECEIVED received configuration: %1
A debug message listing the configuration received by the DHCPv6 server.
The source of that configuration depends on used configuration backend.
......
This diff is collapsed.
......@@ -462,61 +462,62 @@ namespace isc { namespace dhcp {
TOKEN_CONTROL_SOCKET = 370,
TOKEN_SOCKET_TYPE = 371,
TOKEN_SOCKET_NAME = 372,
TOKEN_DHCP_DDNS = 373,
TOKEN_ENABLE_UPDATES = 374,
TOKEN_QUALIFYING_SUFFIX = 375,
TOKEN_SERVER_IP = 376,
TOKEN_SERVER_PORT = 377,
TOKEN_SENDER_IP = 378,
TOKEN_SENDER_PORT = 379,
TOKEN_MAX_QUEUE_SIZE = 380,
TOKEN_NCR_PROTOCOL = 381,
TOKEN_NCR_FORMAT = 382,
TOKEN_ALWAYS_INCLUDE_FQDN = 383,
TOKEN_OVERRIDE_NO_UPDATE = 384,
TOKEN_OVERRIDE_CLIENT_UPDATE = 385,
TOKEN_REPLACE_CLIENT_NAME = 386,
TOKEN_GENERATED_PREFIX = 387,
TOKEN_UDP = 388,
TOKEN_TCP = 389,
TOKEN_JSON = 390,
TOKEN_WHEN_PRESENT = 391,
TOKEN_NEVER = 392,
TOKEN_ALWAYS = 393,
TOKEN_WHEN_NOT_PRESENT = 394,
TOKEN_HOSTNAME_CHAR_SET = 395,
TOKEN_HOSTNAME_CHAR_REPLACEMENT = 396,
TOKEN_LOGGING = 397,
TOKEN_LOGGERS = 398,
TOKEN_OUTPUT_OPTIONS = 399,
TOKEN_OUTPUT = 400,
TOKEN_DEBUGLEVEL = 401,
TOKEN_SEVERITY = 402,
TOKEN_FLUSH = 403,
TOKEN_MAXSIZE = 404,
TOKEN_MAXVER = 405,
TOKEN_DHCP4 = 406,
TOKEN_DHCPDDNS = 407,
TOKEN_CONTROL_AGENT = 408,
TOKEN_TOPLEVEL_JSON = 409,
TOKEN_TOPLEVEL_DHCP6 = 410,
TOKEN_SUB_DHCP6 = 411,
TOKEN_SUB_INTERFACES6 = 412,
TOKEN_SUB_SUBNET6 = 413,
TOKEN_SUB_POOL6 = 414,
TOKEN_SUB_PD_POOL = 415,
TOKEN_SUB_RESERVATION = 416,
TOKEN_SUB_OPTION_DEFS = 417,
TOKEN_SUB_OPTION_DEF = 418,
TOKEN_SUB_OPTION_DATA = 419,
TOKEN_SUB_HOOKS_LIBRARY = 420,
TOKEN_SUB_DHCP_DDNS = 421,
TOKEN_SUB_LOGGING = 422,
TOKEN_SUB_CONFIG_CONTROL = 423,
TOKEN_STRING = 424,
TOKEN_INTEGER = 425,
TOKEN_FLOAT = 426,
TOKEN_BOOLEAN = 427
TOKEN_QUEUE_CONTROL = 373,
TOKEN_DHCP_DDNS = 374,
TOKEN_ENABLE_UPDATES = 375,
TOKEN_QUALIFYING_SUFFIX = 376,
TOKEN_SERVER_IP = 377,
TOKEN_SERVER_PORT = 378,
TOKEN_SENDER_IP = 379,
TOKEN_SENDER_PORT = 380,
TOKEN_MAX_QUEUE_SIZE = 381,
TOKEN_NCR_PROTOCOL = 382,
TOKEN_NCR_FORMAT = 383,
TOKEN_ALWAYS_INCLUDE_FQDN = 384,
TOKEN_OVERRIDE_NO_UPDATE = 385,
TOKEN_OVERRIDE_CLIENT_UPDATE = 386,
TOKEN_REPLACE_CLIENT_NAME = 387,
TOKEN_GENERATED_PREFIX = 388,
TOKEN_UDP = 389,
TOKEN_TCP = 390,
TOKEN_JSON = 391,
TOKEN_WHEN_PRESENT = 392,
TOKEN_NEVER = 393,
TOKEN_ALWAYS = 394,
TOKEN_WHEN_NOT_PRESENT = 395,
TOKEN_HOSTNAME_CHAR_SET = 396,
TOKEN_HOSTNAME_CHAR_REPLACEMENT = 397,
TOKEN_LOGGING = 398,
TOKEN_LOGGERS = 399,
TOKEN_OUTPUT_OPTIONS = 400,
TOKEN_OUTPUT = 401,
TOKEN_DEBUGLEVEL = 402,
TOKEN_SEVERITY = 403,
TOKEN_FLUSH = 404,
TOKEN_MAXSIZE = 405,
TOKEN_MAXVER = 406,
TOKEN_DHCP4 = 407,
TOKEN_DHCPDDNS = 408,
TOKEN_CONTROL_AGENT = 409,
TOKEN_TOPLEVEL_JSON = 410,
TOKEN_TOPLEVEL_DHCP6 = 411,
TOKEN_SUB_DHCP6 = 412,
TOKEN_SUB_INTERFACES6 = 413,
TOKEN_SUB_SUBNET6 = 414,
TOKEN_SUB_POOL6 = 415,
TOKEN_SUB_PD_POOL = 416,
TOKEN_SUB_RESERVATION = 417,
TOKEN_SUB_OPTION_DEFS = 418,
TOKEN_SUB_OPTION_DEF = 419,
TOKEN_SUB_OPTION_DATA = 420,
TOKEN_SUB_HOOKS_LIBRARY = 421,
TOKEN_SUB_DHCP_DDNS = 422,
TOKEN_SUB_LOGGING = 423,
TOKEN_SUB_CONFIG_CONTROL = 424,
TOKEN_STRING = 425,
TOKEN_INTEGER = 426,
TOKEN_FLOAT = 427,
TOKEN_BOOLEAN = 428
};
};
......@@ -1095,6 +1096,10 @@ namespace isc { namespace dhcp {
symbol_type
make_SOCKET_NAME (const location_type& l);
static inline
symbol_type
make_QUEUE_CONTROL (const location_type& l);
static inline
symbol_type
make_DHCP_DDNS (const location_type& l);
......@@ -1520,12 +1525,12 @@ namespace isc { namespace dhcp {
enum
{
yyeof_ = 0,
yylast_ = 1017, ///< Last index in yytable_.
yynnts_ = 389, ///< Number of nonterminal symbols.
yylast_ = 1022, ///< Last index in yytable_.
yynnts_ = 391, ///< Number of nonterminal symbols.
yyfinal_ = 32, ///< Termination state number.
yyterror_ = 1,
yyerrcode_ = 256,
yyntokens_ = 173 ///< Number of tokens.
yyntokens_ = 174 ///< Number of tokens.
};
......@@ -1584,9 +1589,9 @@ namespace isc { namespace dhcp {
135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
165, 166, 167, 168, 169, 170, 171, 172
165, 166, 167, 168, 169, 170, 171, 172, 173
};
const unsigned int user_token_number_max_ = 427;
const unsigned int user_token_number_max_ = 428;
const token_number_type undef_token_ = 2;
if (static_cast<int>(t) <= yyeof_)
......@@ -1619,29 +1624,29 @@ namespace isc { namespace dhcp {
{
switch (other.type_get ())
{
case 190: // value
case 194: // map_value
case 246: // db_type
case 335: // hr_mode
case 471: // duid_type
case 504: // ncr_protocol_value
case 512: // replace_client_name_value
case 191: // value
case 195: // map_value
case 247: // db_type
case 336: // hr_mode
case 472: // duid_type
case 507: // ncr_protocol_value
case 515: // replace_client_name_value
value.copy< ElementPtr > (other.value);
break;
case 172: // "boolean"
case 173: // "boolean"
value.copy< bool > (other.value);
break;
case 171: // "floating point"
case 172: // "floating point"
value.copy< double > (other.value);
break;
case 170: // "integer"
case 171: // "integer"
value.copy< int64_t > (other.value);
break;
case 169: // "constant string"
case 170: // "constant string"
value.copy< std::string > (other.value);
break;
......@@ -1662,29 +1667,29 @@ namespace isc { namespace dhcp {
(void) v;
switch (this->type_get ())
{
case 190: // value
case 194: // map_value
case 246: // db_type
case 335: // hr_mode
case 471: // duid_type
case 504: // ncr_protocol_value
case 512: // replace_client_name_value
case 191: // value
case 195: // map_value
case 247: // db_type
case 336: // hr_mode
case 472: // duid_type
case 507: // ncr_protocol_value
case 515: // replace_client_name_value
value.copy< ElementPtr > (v);
break;
case 172: // "boolean"
case 173: // "boolean"
value.copy< bool > (v);
break;
case 171: // "floating point"
case 172: // "floating point"
value.copy< double > (v);
break;
case 170: // "integer"
case 171: // "integer"
value.copy< int64_t > (v);
break;
case 169: // "constant string"
case 170: // "constant string"
value.copy< std::string > (v);
break;
......@@ -1764,29 +1769,29 @@ namespace isc { namespace dhcp {
// Type destructor.
switch (yytype)
{
case 190: // value
case 194: // map_value
case 246: // db_type
case 335: // hr_mode
case 471: // duid_type
case 504: // ncr_protocol_value
case 512: // replace_client_name_value
case 191: // value
case 195: // map_value
case 247: // db_type
case 336: // hr_mode
case 472: // duid_type
case 507: // ncr_protocol_value
case 515: // replace_client_name_value
value.template destroy< ElementPtr > ();
break;
case 172: // "boolean"
case 173: // "boolean"
value.template destroy< bool > ();
break;
case 171: // "floating point"
case 172: // "floating point"
value.template destroy< double > ();
break;
case 170: // "integer"
case 171: // "integer"
value.template destroy< int64_t > ();
break;
case 169: // "constant string"
case 170: // "constant string"
value.template destroy< std::string > ();
break;
......@@ -1813,29 +1818,29 @@ namespace isc { namespace dhcp {
super_type::move(s);
switch (this->type_get ())
{
case 190: // value
case 194: // map_value
case 246: // db_type
case 335: // hr_mode
case 471: // duid_type
case 504: // ncr_protocol_value
case 512: // replace_client_name_value
case 191: // value
case 195: // map_value
case 247: // db_type
case 336: // hr_mode
case 472: // duid_type
case 507: // ncr_protocol_value
case 515: // replace_client_name_value
value.move< ElementPtr > (s.value);
break;
case 172: // "boolean"
case 173: // "boolean"
value.move< bool > (s.value);
break;
case 171: // "floating point"
case 172: // "floating point"
value.move< double > (s.value);
break;
case 170: // "integer"
case 171: // "integer"
value.move< int64_t > (s.value);
break;
case 169: // "constant string"
case 170: // "constant string"
value.move< std::string > (s.value);
break;
......@@ -1911,7 +1916,7 @@ namespace isc { namespace dhcp {
395, 396, 397, 398, 399, 400, 401, 402, 403, 404,
405, 406, 407, 408, 409, 410, 411, 412, 413, 414,
415, 416, 417, 418, 419, 420, 421, 422, 423, 424,
425, 426, 427
425, 426, 427, 428
};
return static_cast<token_type> (yytoken_number_[type]);
}
......@@ -2612,6 +2617,12 @@ namespace isc { namespace dhcp {
return symbol_type (token::TOKEN_SOCKET_NAME, l);
}
Dhcp6Parser::symbol_type
Dhcp6Parser::make_QUEUE_CONTROL (const location_type& l)
{
return symbol_type (token::TOKEN_QUEUE_CONTROL, l);
}
Dhcp6Parser::symbol_type
Dhcp6Parser::make_DHCP_DDNS (const location_type& l)
{
......@@ -2945,7 +2956,7 @@ namespace isc { namespace dhcp {
#line 14 "dhcp6_parser.yy" // lalr1.cc:377
} } // isc::dhcp
#line 2949 "dhcp6_parser.h" // lalr1.cc:377
#line 2960 "dhcp6_parser.h" // lalr1.cc:377
......
......@@ -172,6 +172,8 @@ using namespace std;
SOCKET_TYPE "socket-type"
SOCKET_NAME "socket-name"
QUEUE_CONTROL "queue-control"
DHCP_DDNS "dhcp-ddns"
ENABLE_UPDATES "enable-updates"
QUALIFYING_SUFFIX "qualifying-suffix"
......@@ -455,6 +457,7 @@ global_param: preferred_lifetime
| server_id
| dhcp4o6_port
| control_socket
| queue_control
| dhcp_ddns
| user_context
| comment
......@@ -1920,6 +1923,22 @@ socket_name: SOCKET_NAME {
ctx.leave();
};
queue_control: QUEUE_CONTROL {
ctx.enter(ctx.NO_KEYWORD);
} COLON map_value {
ElementPtr qc = $4;
ctx.stack_.back()->set("queue-control", qc);
if (!qc->contains("queue-type")) {
std::stringstream msg;
msg << "'queue-type' is required: ";
msg << qc->getPosition().str() << ")";
error(@1, msg.str());
}
ctx.leave();
};
// --- dhcp ddns ---------------------------------------------
dhcp_ddns: DHCP_DDNS {
......
......@@ -31,6 +31,7 @@
#include <dhcpsrv/parsers/host_reservations_list_parser.h>
#include <dhcpsrv/parsers/ifaces_config_parser.h>
#include <dhcpsrv/parsers/option_data_parser.h>
#include <dhcpsrv/parsers/queue_control_parser.h>
#include <dhcpsrv/parsers/simple_parser6.h>
#include <dhcpsrv/parsers/shared_networks_list_parser.h>
#include <dhcpsrv/parsers/sanity_checks_parser.h>
......@@ -482,6 +483,12 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
continue;
}
if (config_pair.first == "queue-control") {
QueueControlParser parser(AF_INET);
srv_config->setQueueControlInfo(parser.parse(config_pair.second));
continue;
}
if (config_pair.first == "host-reservation-identifiers") {
HostReservationIdsParser6 parser;
parser.parse(config_pair.second);
......
......@@ -174,6 +174,8 @@ Parser6Context::contextName()
return ("duid-type");
case CONTROL_SOCKET:
return ("control-socket");
case QUEUE_CONTROL:
return ("queue-control");
case POOLS:
return ("pools");
case PD_POOLS:
......
......@@ -271,6 +271,9 @@ public:
/// Used while parsing Dhcp6/control-socket structures.
CONTROL_SOCKET,
/// Used while parsing Dhcp4/queue-control structures.
QUEUE_CONTROL,
/// Used while parsing Dhcp6/subnet6/pools structures.
POOLS,
......
......@@ -6915,4 +6915,110 @@ TEST_F(Dhcp6ParserTest, serverTag) {
ASSERT_THROW(parseDHCP6(bad_tag), std::exception);
}
// Check whether it is possible to configure queue-control
TEST_F(Dhcp6ParserTest, queueControl) {
// Config without server-tag
string config_no_queue = "{ " + genIfaceConfig() + "," +
"\"subnet6\": [ ] "
"}";
string config_with_queue =
"{ " + genIfaceConfig() + ", \n" +
" \"subnet6\": [ ], \n"
" \"queue-control\": { \n"
" \"queue-type\": \"some-type\", \n"
" \"capacity\": 75 \n"
" } \n"
"} \n";
string config_with_context =
"{ " + genIfaceConfig() + ", \n" +
" \"subnet6\": [ ], \n"
" \"queue-control\": { \n"
" \"queue-type\": \"some-type\", \n"
" \"capacity\": 90, \n"
" \"user-context\": { \"comment\": \"some text\" } \n"
" } \n"
"} \n";
// Let's check the default. It should be empty.
data::ConstElementPtr control;
control = CfgMgr::instance().getStagingCfg()->getQueueControlInfo();
ASSERT_FALSE(control);
// Configuration with no queue should default to an emtpy control.
configure(config_no_queue, CONTROL_RESULT_SUCCESS, "");
control = CfgMgr::instance().getStagingCfg()->getQueueControlInfo();
ASSERT_FALSE(control);
// Clear the config
CfgMgr::instance().clear();
// Configuration with queue should be valid.
configure(config_with_queue, CONTROL_RESULT_SUCCESS, "");
control = CfgMgr::instance().getStagingCfg()->getQueueControlInfo();
ASSERT_TRUE(control);
// Clear the config
CfgMgr::instance().clear();
// Configuration with queue with context should be valid.
configure(config_with_context, CONTROL_RESULT_SUCCESS, "");
control = CfgMgr::instance().getStagingCfg()->getQueueControlInfo();
ASSERT_TRUE(control);
}
// Check whether it is possible to configure server-tag
TEST_F(Dhcp6ParserTest, queueControlInvalid) {
struct Scenario {
std::string description_;
std::string json_;
};
std::vector<Scenario> scenarios = {
{
"not a map",
"{ " + genIfaceConfig() + ", \n" +
" \"subnet6\": [ ], \n"
" \"queue-control\": 75 \n"
"} \n"
},
{
"queue type missing",
"{ " + genIfaceConfig() + ", \n" +
" \"subnet6\": [ ], \n"
" \"queue-control\": { \n"
" \"capacity\": 100 \n"
" } \n"
"} \n"
},
{
"capacity missing",
"{ " + genIfaceConfig() + ", \n" +
" \"subnet6\": [ ], \n"
" \"queue-control\": {} \n"
"} \n"
},
{
"capacity not an int",
"{ " + genIfaceConfig() + ", \n" +
" \"subnet6\": [ ], \n"
" \"queue-control\": { \n"
" \"capacity\": \"ninety\", \n"
" } \n"
"} \n"
}
};
// Iterate over the incorrect scenarios and verify they
// fail as expected. Note, we use parseDHCP6() directly
// as all of the errors above are enforced by the grammar.
for (auto scenario : scenarios) {
SCOPED_TRACE((scenario).description_);
{
EXPECT_THROW(parseDHCP6((scenario).json_), Dhcp6ParseError);
}
}
}
};
......@@ -29,8 +29,6 @@ QueueControlParser::QueueControlParser(const uint16_t family)