Commit 036d249f authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

[#42, !103] Interrim commit, kea-dhcp4 supports "queue-control"

    kea-dhcp4 will parse and use "queue-control" to configure ring
    buffer size:

    "Dhcp4":
    {
        "queue-control": {
            # max number of packets the ring will hold
            "capacity" : 100
        },
    :

    This is an interrim commit for testing purposes.
    Expect a fair amount of refactoring in subsequent commits.

New files:
	src/lib/dhcp/queue_control.cc
	src/lib/dhcp/queue_control.h
	src/lib/dhcp/tests/queue_control_unittest.cc
	src/lib/dhcpsrv/parsers/queue_control_parser.cc
	src/lib/dhcpsrv/parsers/queue_control_parser.h

src/bin/dhcp4/ctrl_dhcp4_srv.cc
    ControlledDhcpv4Srv::processConfig() -
        added logic to set packet queue controller

src/bin/dhcp4/dhcp4_lexer.ll b/src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp4/parser_context.*
    Added queue-control parsing

src/bin/dhcp4/json_config_parser.cc
    configureDhcp4Server() - recognize and parse "queue-control"

src/bin/dhcp4/tests/config_parser_unittest.cc
    TEST_F(Dhcp4ParserTest, queueControl)
    TEST_F(Dhcp4ParserTest, queueControlInvalid)
    - new tests

src/lib/dhcp/iface_mgr.*
    IfaceMgr::getPacketQueueControl4()
    IfaceMgr::setPacketQueueControl4()
    IfaceMgr::getPacketQueueControl6()
    IfaceMgr::setPacketQueueControl6()

src/lib/dhcp/packet_queue.*
    Use QueueControl class

src/lib/dhcpsrv/srv_config.*
    Added QueueControl member, getter/setter
    SrvConfig::toElement() - now emits queue-control if not null
parent 21cac7d0
......@@ -634,6 +634,26 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
return (isc::config::createAnswer(1, err.str()));
}
try {
// @todo Consider making this a function and consider whether
// it should check for old gc != null and new gc null before
// calling setPacketQueueControl(). Or if we should even
// call it when it's null?
// Still grappling with what to if there is a custom queue
// loaded. Could have a flag in the control that means
// using custom impl, in which case we don't make the call
// at all. ... I dunno
ConstQueueControlPtr qc;
qc = CfgMgr::instance().getStagingCfg()->getQueueControlInfo();
IfaceMgr::instance().setPacketQueueControl4(qc);
qc = IfaceMgr::instance().getPacketQueueControl4();
std::cout << "TKM using capacity: " << qc->getCapacity() << std::endl;
} catch (const std::exception& ex) {
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.
......@@ -706,6 +706,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
case isc::dhcp::Parser4Context::RESERVATIONS:
case isc::dhcp::Parser4Context::CLIENT_CLASSES:
case isc::dhcp::Parser4Context::CONTROL_SOCKET:
case isc::dhcp::Parser4Context::QUEUE_CONTROL:
case isc::dhcp::Parser4Context::LOGGERS:
case isc::dhcp::Parser4Context::DHCP_DDNS:
return isc::dhcp::Dhcp4Parser::make_USER_CONTEXT(driver.loc_);
......@@ -726,6 +727,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
case isc::dhcp::Parser4Context::RESERVATIONS:
case isc::dhcp::Parser4Context::CLIENT_CLASSES:
case isc::dhcp::Parser4Context::CONTROL_SOCKET:
case isc::dhcp::Parser4Context::QUEUE_CONTROL:
case isc::dhcp::Parser4Context::LOGGERS:
case isc::dhcp::Parser4Context::DHCP_DDNS:
return isc::dhcp::Dhcp4Parser::make_COMMENT(driver.loc_);
......@@ -1239,6 +1241,24 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"queue-control\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
return isc::dhcp::Dhcp4Parser::make_QUEUE_CONTROL(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("queue-control", driver.loc_);
}
}
\"capacity\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::QUEUE_CONTROL:
return isc::dhcp::Dhcp4Parser::make_CAPACITY(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("capacity", driver.loc_);
}
}
\"dhcp-ddns\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
......
This diff is collapsed.
......@@ -460,59 +460,61 @@ namespace isc { namespace dhcp {
TOKEN_CONTROL_SOCKET = 367,
TOKEN_SOCKET_TYPE = 368,
TOKEN_SOCKET_NAME = 369,
TOKEN_DHCP_DDNS = 370,
TOKEN_ENABLE_UPDATES = 371,
TOKEN_QUALIFYING_SUFFIX = 372,
TOKEN_SERVER_IP = 373,
TOKEN_SERVER_PORT = 374,
TOKEN_SENDER_IP = 375,
TOKEN_SENDER_PORT = 376,
TOKEN_MAX_QUEUE_SIZE = 377,
TOKEN_NCR_PROTOCOL = 378,
TOKEN_NCR_FORMAT = 379,
TOKEN_ALWAYS_INCLUDE_FQDN = 380,
TOKEN_OVERRIDE_NO_UPDATE = 381,
TOKEN_OVERRIDE_CLIENT_UPDATE = 382,
TOKEN_REPLACE_CLIENT_NAME = 383,
TOKEN_GENERATED_PREFIX = 384,
TOKEN_TCP = 385,
TOKEN_JSON = 386,
TOKEN_WHEN_PRESENT = 387,
TOKEN_NEVER = 388,
TOKEN_ALWAYS = 389,
TOKEN_WHEN_NOT_PRESENT = 390,
TOKEN_HOSTNAME_CHAR_SET = 391,
TOKEN_HOSTNAME_CHAR_REPLACEMENT = 392,
TOKEN_LOGGING = 393,
TOKEN_LOGGERS = 394,
TOKEN_OUTPUT_OPTIONS = 395,
TOKEN_OUTPUT = 396,
TOKEN_DEBUGLEVEL = 397,
TOKEN_SEVERITY = 398,
TOKEN_FLUSH = 399,
TOKEN_MAXSIZE = 400,
TOKEN_MAXVER = 401,
TOKEN_DHCP6 = 402,
TOKEN_DHCPDDNS = 403,
TOKEN_CONTROL_AGENT = 404,
TOKEN_TOPLEVEL_JSON = 405,
TOKEN_TOPLEVEL_DHCP4 = 406,
TOKEN_SUB_DHCP4 = 407,
TOKEN_SUB_INTERFACES4 = 408,
TOKEN_SUB_SUBNET4 = 409,
TOKEN_SUB_POOL4 = 410,
TOKEN_SUB_RESERVATION = 411,
TOKEN_SUB_OPTION_DEFS = 412,
TOKEN_SUB_OPTION_DEF = 413,
TOKEN_SUB_OPTION_DATA = 414,
TOKEN_SUB_HOOKS_LIBRARY = 415,
TOKEN_SUB_DHCP_DDNS = 416,
TOKEN_SUB_LOGGING = 417,
TOKEN_SUB_CONFIG_CONTROL = 418,
TOKEN_STRING = 419,
TOKEN_INTEGER = 420,
TOKEN_FLOAT = 421,
TOKEN_BOOLEAN = 422
TOKEN_QUEUE_CONTROL = 370,
TOKEN_CAPACITY = 371,
TOKEN_DHCP_DDNS = 372,
TOKEN_ENABLE_UPDATES = 373,
TOKEN_QUALIFYING_SUFFIX = 374,
TOKEN_SERVER_IP = 375,
TOKEN_SERVER_PORT = 376,
TOKEN_SENDER_IP = 377,
TOKEN_SENDER_PORT = 378,
TOKEN_MAX_QUEUE_SIZE = 379,
TOKEN_NCR_PROTOCOL = 380,
TOKEN_NCR_FORMAT = 381,
TOKEN_ALWAYS_INCLUDE_FQDN = 382,
TOKEN_OVERRIDE_NO_UPDATE = 383,
TOKEN_OVERRIDE_CLIENT_UPDATE = 384,
TOKEN_REPLACE_CLIENT_NAME = 385,
TOKEN_GENERATED_PREFIX = 386,
TOKEN_TCP = 387,
TOKEN_JSON = 388,
TOKEN_WHEN_PRESENT = 389,
TOKEN_NEVER = 390,
TOKEN_ALWAYS = 391,
TOKEN_WHEN_NOT_PRESENT = 392,
TOKEN_HOSTNAME_CHAR_SET = 393,
TOKEN_HOSTNAME_CHAR_REPLACEMENT = 394,
TOKEN_LOGGING = 395,
TOKEN_LOGGERS = 396,
TOKEN_OUTPUT_OPTIONS = 397,
TOKEN_OUTPUT = 398,
TOKEN_DEBUGLEVEL = 399,
TOKEN_SEVERITY = 400,
TOKEN_FLUSH = 401,
TOKEN_MAXSIZE = 402,
TOKEN_MAXVER = 403,
TOKEN_DHCP6 = 404,
TOKEN_DHCPDDNS = 405,
TOKEN_CONTROL_AGENT = 406,
TOKEN_TOPLEVEL_JSON = 407,
TOKEN_TOPLEVEL_DHCP4 = 408,
TOKEN_SUB_DHCP4 = 409,
TOKEN_SUB_INTERFACES4 = 410,
TOKEN_SUB_SUBNET4 = 411,
TOKEN_SUB_POOL4 = 412,
TOKEN_SUB_RESERVATION = 413,
TOKEN_SUB_OPTION_DEFS = 414,
TOKEN_SUB_OPTION_DEF = 415,
TOKEN_SUB_OPTION_DATA = 416,
TOKEN_SUB_HOOKS_LIBRARY = 417,
TOKEN_SUB_DHCP_DDNS = 418,
TOKEN_SUB_LOGGING = 419,
TOKEN_SUB_CONFIG_CONTROL = 420,
TOKEN_STRING = 421,
TOKEN_INTEGER = 422,
TOKEN_FLOAT = 423,
TOKEN_BOOLEAN = 424
};
};
......@@ -1079,6 +1081,14 @@ 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_CAPACITY (const location_type& l);
static inline
symbol_type
make_DHCP_DDNS (const location_type& l);
......@@ -1496,12 +1506,12 @@ namespace isc { namespace dhcp {
enum
{
yyeof_ = 0,
yylast_ = 983, ///< Last index in yytable_.
yynnts_ = 372, ///< Number of nonterminal symbols.
yylast_ = 1005, ///< Last index in yytable_.
yynnts_ = 377, ///< Number of nonterminal symbols.
yyfinal_ = 30, ///< Termination state number.
yyterror_ = 1,
yyerrcode_ = 256,
yyntokens_ = 168 ///< Number of tokens.
yyntokens_ = 170 ///< Number of tokens.
};
......@@ -1560,9 +1570,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
165, 166, 167, 168, 169
};
const unsigned int user_token_number_max_ = 422;
const unsigned int user_token_number_max_ = 424;
const token_number_type undef_token_ = 2;
if (static_cast<int>(t) <= yyeof_)
......@@ -1595,30 +1605,30 @@ namespace isc { namespace dhcp {
{
switch (other.type_get ())
{
case 184: // value
case 188: // map_value
case 228: // socket_type
case 231: // outbound_interface_value
case 253: // db_type
case 335: // hr_mode
case 482: // ncr_protocol_value
case 490: // replace_client_name_value
case 186: // value
case 190: // map_value
case 230: // socket_type
case 233: // outbound_interface_value
case 255: // db_type
case 337: // hr_mode
case 489: // ncr_protocol_value
case 497: // replace_client_name_value
value.copy< ElementPtr > (other.value);
break;
case 167: // "boolean"
case 169: // "boolean"
value.copy< bool > (other.value);
break;
case 166: // "floating point"
case 168: // "floating point"
value.copy< double > (other.value);
break;
case 165: // "integer"
case 167: // "integer"
value.copy< int64_t > (other.value);
break;
case 164: // "constant string"
case 166: // "constant string"
value.copy< std::string > (other.value);
break;
......@@ -1639,30 +1649,30 @@ namespace isc { namespace dhcp {
(void) v;
switch (this->type_get ())
{
case 184: // value
case 188: // map_value
case 228: // socket_type
case 231: // outbound_interface_value
case 253: // db_type
case 335: // hr_mode
case 482: // ncr_protocol_value
case 490: // replace_client_name_value
case 186: // value
case 190: // map_value
case 230: // socket_type
case 233: // outbound_interface_value
case 255: // db_type
case 337: // hr_mode
case 489: // ncr_protocol_value
case 497: // replace_client_name_value
value.copy< ElementPtr > (v);
break;
case 167: // "boolean"
case 169: // "boolean"
value.copy< bool > (v);
break;
case 166: // "floating point"
case 168: // "floating point"
value.copy< double > (v);
break;
case 165: // "integer"
case 167: // "integer"
value.copy< int64_t > (v);
break;
case 164: // "constant string"
case 166: // "constant string"
value.copy< std::string > (v);
break;
......@@ -1742,30 +1752,30 @@ namespace isc { namespace dhcp {
// Type destructor.
switch (yytype)
{
case 184: // value
case 188: // map_value
case 228: // socket_type
case 231: // outbound_interface_value
case 253: // db_type
case 335: // hr_mode
case 482: // ncr_protocol_value
case 490: // replace_client_name_value
case 186: // value
case 190: // map_value
case 230: // socket_type
case 233: // outbound_interface_value
case 255: // db_type
case 337: // hr_mode
case 489: // ncr_protocol_value
case 497: // replace_client_name_value
value.template destroy< ElementPtr > ();
break;
case 167: // "boolean"
case 169: // "boolean"
value.template destroy< bool > ();
break;
case 166: // "floating point"
case 168: // "floating point"
value.template destroy< double > ();
break;
case 165: // "integer"
case 167: // "integer"
value.template destroy< int64_t > ();
break;
case 164: // "constant string"
case 166: // "constant string"
value.template destroy< std::string > ();
break;
......@@ -1792,30 +1802,30 @@ namespace isc { namespace dhcp {
super_type::move(s);
switch (this->type_get ())
{
case 184: // value
case 188: // map_value
case 228: // socket_type
case 231: // outbound_interface_value
case 253: // db_type
case 335: // hr_mode
case 482: // ncr_protocol_value
case 490: // replace_client_name_value
case 186: // value
case 190: // map_value
case 230: // socket_type
case 233: // outbound_interface_value
case 255: // db_type
case 337: // hr_mode
case 489: // ncr_protocol_value
case 497: // replace_client_name_value
value.move< ElementPtr > (s.value);
break;
case 167: // "boolean"
case 169: // "boolean"
value.move< bool > (s.value);
break;
case 166: // "floating point"
case 168: // "floating point"
value.move< double > (s.value);
break;
case 165: // "integer"
case 167: // "integer"
value.move< int64_t > (s.value);
break;
case 164: // "constant string"
case 166: // "constant string"
value.move< std::string > (s.value);
break;
......@@ -1890,7 +1900,7 @@ namespace isc { namespace dhcp {
385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
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
415, 416, 417, 418, 419, 420, 421, 422, 423, 424
};
return static_cast<token_type> (yytoken_number_[type]);
}
......@@ -2573,6 +2583,18 @@ namespace isc { namespace dhcp {
return symbol_type (token::TOKEN_SOCKET_NAME, l);
}
Dhcp4Parser::symbol_type
Dhcp4Parser::make_QUEUE_CONTROL (const location_type& l)
{
return symbol_type (token::TOKEN_QUEUE_CONTROL, l);
}
Dhcp4Parser::symbol_type
Dhcp4Parser::make_CAPACITY (const location_type& l)
{
return symbol_type (token::TOKEN_CAPACITY, l);
}
Dhcp4Parser::symbol_type
Dhcp4Parser::make_DHCP_DDNS (const location_type& l)
{
......@@ -2894,7 +2916,7 @@ namespace isc { namespace dhcp {
#line 14 "dhcp4_parser.yy" // lalr1.cc:377
} } // isc::dhcp
#line 2898 "dhcp4_parser.h" // lalr1.cc:377
#line 2920 "dhcp4_parser.h" // lalr1.cc:377
......
......@@ -170,6 +170,9 @@ using namespace std;
SOCKET_TYPE "socket-type"
SOCKET_NAME "socket-name"
QUEUE_CONTROL "queue-control"
CAPACITY "capacity"
DHCP_DDNS "dhcp-ddns"
ENABLE_UPDATES "enable-updates"
QUALIFYING_SUFFIX "qualifying-suffix"
......@@ -448,6 +451,7 @@ global_param: valid_lifetime
| expired_leases_processing
| dhcp4o6_port
| control_socket
| queue_control
| dhcp_ddns
| echo_client_id
| match_client_id
......@@ -1823,6 +1827,35 @@ control_socket_name: SOCKET_NAME {
ctx.leave();
};
// --- queue control ---------------------------------------------
queue_control: QUEUE_CONTROL {
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("queue-control", m);
ctx.stack_.push_back(m);
ctx.enter(ctx.QUEUE_CONTROL);
} COLON LCURLY_BRACKET queue_control_params RCURLY_BRACKET {
ctx.require("capacity", ctx.loc2pos(@4), ctx.loc2pos(@6));
ctx.stack_.pop_back();
ctx.leave();
};
queue_control_params: queue_control_param
| queue_control_params COMMA queue_control_param
;
queue_control_param: capacity
| user_context
| comment
| unknown_map_entry
;
capacity: CAPACITY COLON INTEGER {
ElementPtr i(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("capacity", i);
};
// --- dhcp ddns ---------------------------------------------
dhcp_ddns: DHCP_DDNS {
......
......@@ -24,6 +24,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_parser4.h>
#include <dhcpsrv/parsers/shared_networks_list_parser.h>
#include <dhcpsrv/parsers/sanity_checks_parser.h>
......@@ -380,6 +381,13 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
continue;
}
if (config_pair.first == "queue-control") {
QueueControlParser parser(AF_INET);
QueueControlPtr queue_control = parser.parse(config_pair.second);
srv_cfg->setQueueControlInfo(queue_control);
continue;
}
if (config_pair.first == "host-reservation-identifiers") {
HostReservationIdsParser4 parser;
parser.parse(config_pair.second);
......
......@@ -174,6 +174,8 @@ Parser4Context::contextName()
return ("server-id");
case CONTROL_SOCKET:
return ("control-socket");
case QUEUE_CONTROL:
return ("queue-control");
case POOLS:
return ("pools");
case RESERVATIONS:
......
......@@ -267,6 +267,9 @@ public:
/// Used while parsing Dhcp4/control-socket structures.
CONTROL_SOCKET,
/// Used while parsing Dhcp4/queue-control structures.
QUEUE_CONTROL,
/// Used while parsing Dhcp4/subnet4/pools structures.
POOLS,
......
......@@ -6337,4 +6337,103 @@ TEST_F(Dhcp4ParserTest, serverTag) {
ASSERT_THROW(parseDHCP4(bad_tag), std::exception);
}
// Check whether it is possible to configure server-tag
TEST_F(Dhcp4ParserTest, queueControl) {
// Config without server-tag
string config_no_queue = "{ " + genIfaceConfig() + "," +
"\"subnet4\": [ ] "
"}";
string config_with_queue =
"{ " + genIfaceConfig() + ", \n" +
" \"subnet4\": [ ], \n"
" \"queue-control\": { \n"
" \"capacity\": 75 \n"
" } \n"
"} \n";
string config_with_context =
"{ " + genIfaceConfig() + ", \n" +
" \"subnet4\": [ ], \n"
" \"queue-control\": { \n"
" \"capacity\": 90, \n"
" \"user-context\": { \"comment\": \"some text\" } \n"
" } \n"
"} \n";
// Let's check the default. It should be empty.
ConstQueueControlPtr 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);
EXPECT_EQ(75, control->getCapacity());
EXPECT_FALSE(control->getContext());
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);
EXPECT_EQ(90, control->getCapacity());
EXPECT_TRUE(control->getContext());
}
// Check whether it is possible to configure server-tag
TEST_F(Dhcp4ParserTest, queueControlInvalid) {
struct Scenario {
std::string description_;
std::string json_;
};
std::vector<Scenario> scenarios = {
{
"not a map",
"{ " + genIfaceConfig() + ", \n" +
" \"subnet4\": [ ], \n"
" \"queue-control\": 75 \n"
"} \n"