Commit 78b8edb6 authored by Thomas Markwalder's avatar Thomas Markwalder

[5477] kea-dhcp6 now supports db reconnect

    kea-dhcp6
        added support for max-reconnect-tries and reconnect-wait-time
        to lease and host db parsers

        Added a callback for when DB backends detect loss of connectivity

        Added a self-rescheduling method to attempt to reconnect to the
        backends if retries are enabled

    dhcpsrv
        PgSqlConnection::checkStatementError() - Modified "fatal" logic
        to throw after invoking db_lost_callback.

    Misc. cleanup
parent 249219f1
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -18,7 +18,6 @@
#include <hooks/hooks_manager.h>
#include <stats/stats_mgr.h>
#include <cfgrpt/config_report.h>
#include <boost/lexical_cast.hpp>
#include <signal.h>
#include <sstream>
......@@ -544,83 +543,6 @@ ControlledDhcpv4Srv::processCommand(const string& command,
}
}
void
ControlledDhcpv4Srv::dbReconnect() {
bool reopened = false;
// Re-open lease and host database with new parameters.
try {
CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
cfg_db->createManagers(boost::bind(&ControlledDhcpv4Srv::dbLostCallback, this, _1));
reopened = true;
} catch (const std::exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_DB_RECONNECT_ATTEMPT_FAILED).arg(ex.what());
}
if (reopened) {
// Cancel the timer.
if (TimerMgr::instance()->isTimerRegistered("Dhcp4DbReconnectTimer")) {
TimerMgr::instance()->cancel("Dhcp4DbReconnectTimer");
}
// Set network state to service enabled
network_state_.enableService();
// Toss the reconnct control, we're done with it
db_reconnect_ctl_.reset();
} else {
if (!db_reconnect_ctl_->checkRetries()) {
LOG_ERROR(dhcp4_logger, DHCP4_DB_RECONNECT_RETRIES_EXHAUSTED)
.arg(db_reconnect_ctl_->maxRetries());
shutdown();
return;
}
LOG_INFO(dhcp4_logger, DHCP4_DB_RECONNECT_ATTEMPT_SCHEDULE)
.arg(db_reconnect_ctl_->maxRetries() - db_reconnect_ctl_->retriesLeft())
.arg(db_reconnect_ctl_->maxRetries())
.arg(db_reconnect_ctl_->retryInterval());
if (!TimerMgr::instance()->isTimerRegistered("Dhcp4DbReconnectTimer")) {
TimerMgr::instance()->registerTimer("Dhcp4DbReconnectTimer",
boost::bind(&ControlledDhcpv4Srv::dbReconnect, this),
db_reconnect_ctl_->retryInterval() * 1000,
asiolink::IntervalTimer::ONE_SHOT);
}
TimerMgr::instance()->setup("Dhcp4DbReconnectTimer");
}
}
bool
ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
// Disable service until we recover
network_state_.disableService();
if (!db_reconnect_ctl) {
// This shouldn't never happen
LOG_ERROR(dhcp4_logger, DHCP4_DB_RECONNECT_NO_DB_CTL);
return (false);
}
// If reconnect isn't enabled, log it and return false
if (!db_reconnect_ctl->retriesLeft() ||
!db_reconnect_ctl->retryInterval()) {
LOG_INFO(dhcp4_logger, DHCP4_DB_RECONNECT_DISABLED)
.arg(db_reconnect_ctl->retriesLeft())
.arg(db_reconnect_ctl->retryInterval());
return(false);
}
// Save the reconnect control
db_reconnect_ctl_ = db_reconnect_ctl;
// Invoke reconnect method
dbReconnect();
return(true);
}
isc::data::ConstElementPtr
ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
......@@ -729,7 +651,7 @@ ControlledDhcpv4Srv::checkConfig(isc::data::ConstElementPtr config) {
ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port /*= DHCP4_SERVER_PORT*/)
: Dhcpv4Srv(port), io_service_(), timer_mgr_(TimerMgr::instance()),
db_reconnect_ctl_(0) {
db_reconnect_ctl_(NULL) {
if (getInstance()) {
isc_throw(InvalidOperation,
"There is another Dhcpv4Srv instance already.");
......@@ -872,5 +794,82 @@ ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
TimerMgr::instance()->setup(CfgExpiration::FLUSH_RECLAIMED_TIMER_NAME);
}
void
ControlledDhcpv4Srv::dbReconnect() {
bool reopened = false;
// Re-open lease and host database with new parameters.
try {
CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
cfg_db->createManagers(boost::bind(&ControlledDhcpv4Srv::dbLostCallback, this, _1));
reopened = true;
} catch (const std::exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_DB_RECONNECT_ATTEMPT_FAILED).arg(ex.what());
}
if (reopened) {
// Cancel the timer.
if (TimerMgr::instance()->isTimerRegistered("Dhcp4DbReconnectTimer")) {
TimerMgr::instance()->cancel("Dhcp4DbReconnectTimer");
}
// Set network state to service enabled
network_state_.enableService();
// Toss the reconnct control, we're done with it
db_reconnect_ctl_.reset();
} else {
if (!db_reconnect_ctl_->checkRetries()) {
LOG_ERROR(dhcp4_logger, DHCP4_DB_RECONNECT_RETRIES_EXHAUSTED)
.arg(db_reconnect_ctl_->maxRetries());
shutdown();
return;
}
LOG_INFO(dhcp4_logger, DHCP4_DB_RECONNECT_ATTEMPT_SCHEDULE)
.arg(db_reconnect_ctl_->maxRetries() - db_reconnect_ctl_->retriesLeft() + 1)
.arg(db_reconnect_ctl_->maxRetries())
.arg(db_reconnect_ctl_->retryInterval());
if (!TimerMgr::instance()->isTimerRegistered("Dhcp4DbReconnectTimer")) {
TimerMgr::instance()->registerTimer("Dhcp4DbReconnectTimer",
boost::bind(&ControlledDhcpv4Srv::dbReconnect, this),
db_reconnect_ctl_->retryInterval() * 1000,
asiolink::IntervalTimer::ONE_SHOT);
}
TimerMgr::instance()->setup("Dhcp4DbReconnectTimer");
}
}
bool
ControlledDhcpv4Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
// Disable service until we recover
network_state_.disableService();
if (!db_reconnect_ctl) {
// This shouldn't never happen
LOG_ERROR(dhcp4_logger, DHCP4_DB_RECONNECT_NO_DB_CTL);
return (false);
}
// If reconnect isn't enabled, log it and return false
if (!db_reconnect_ctl->retriesLeft() ||
!db_reconnect_ctl->retryInterval()) {
LOG_INFO(dhcp4_logger, DHCP4_DB_RECONNECT_DISABLED)
.arg(db_reconnect_ctl->retriesLeft())
.arg(db_reconnect_ctl->retryInterval());
return(false);
}
// Save the reconnect control
db_reconnect_ctl_ = db_reconnect_ctl;
// Invoke reconnect method
dbReconnect();
return(true);
}
}; // end of isc::dhcp namespace
}; // end of isc namespace
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -318,6 +318,12 @@ private:
/// deleted.
void deleteExpiredReclaimedLeases(const uint32_t secs);
/// @brief Attempts to reconnect the server to the DB backend managers
void dbReconnect();
/// @brief Callback DB backends should invoke upon loss of connectivity
bool dbLostCallback(ReconnectCtlPtr db_reconnect_ctl);
/// @brief Static pointer to the sole instance of the DHCP server.
///
/// This is required for config and command handlers to gain access to
......@@ -333,12 +339,6 @@ private:
/// make sure that the @c TimerMgr outlives instance of this class.
TimerMgrPtr timer_mgr_;
/// @brief Attempts to reconnect the server to the DB backend managers
void dbReconnect();
/// @brief Callback DB backends should invoke upon loss of connectivity
bool dbLostCallback(ReconnectCtlPtr db_reconnect_ctl);
/// @brief Pointer the current DB reconnect control values
ReconnectCtlPtr db_reconnect_ctl_;
};
......
......@@ -161,7 +161,7 @@ should be reported.
This is an informational message indicating that connetivity to either the
lease or host database or both and that automatic reconnect is not enabled.
% DHCP4_DB_RECONNECT_RETRIES_EXHAUSTED - Maximum number of Database reconnect attempts: %1, hasbeen exhausted without success, server is shutting down!
% DHCP4_DB_RECONNECT_RETRIES_EXHAUSTED - Maximum number of Database reconnect attempts: %1, has been exhausted without success, server is shutting down!
This error indicates that the server is shutting after failing to reconnect to
the lease and/or host database(s) after making the maximum configured number
of reconnect attempts. Loss of connectivity is typically a network or database
......
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -11,6 +11,7 @@
#include <dhcp/libdhcp++.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/cfg_db_access.h>
#include <dhcpsrv/database_connection.h>
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6to4_ipc.h>
#include <dhcp6/dhcp6_log.h>
......@@ -579,8 +580,7 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
try {
CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
cfg_db->setAppendedParameters("universe=6");
cfg_db->createManagers();
cfg_db->createManagers(boost::bind(&ControlledDhcpv6Srv::dbLostCallback, srv, _1));
} catch (const std::exception& ex) {
return (isc::config::createAnswer(1, "Unable to open database: "
+ std::string(ex.what())));
......@@ -673,7 +673,8 @@ ControlledDhcpv6Srv::checkConfig(isc::data::ConstElementPtr config) {
}
ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port)
: Dhcpv6Srv(port), io_service_(), timer_mgr_(TimerMgr::instance()) {
: Dhcpv6Srv(port), io_service_(), timer_mgr_(TimerMgr::instance()),
db_reconnect_ctl_(NULL) {
if (server_) {
isc_throw(InvalidOperation,
"There is another Dhcpv6Srv instance already.");
......@@ -815,6 +816,81 @@ ControlledDhcpv6Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
TimerMgr::instance()->setup(CfgExpiration::FLUSH_RECLAIMED_TIMER_NAME);
}
void
ControlledDhcpv6Srv::dbReconnect() {
bool reopened = false;
// Re-open lease and host database with new parameters.
try {
CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
cfg_db->createManagers(boost::bind(&ControlledDhcpv6Srv::dbLostCallback, this, _1));
reopened = true;
} catch (const std::exception& ex) {
LOG_ERROR(dhcp6_logger, DHCP6_DB_RECONNECT_ATTEMPT_FAILED).arg(ex.what());
}
if (reopened) {
// Cancel the timer.
if (TimerMgr::instance()->isTimerRegistered("Dhcp6DbReconnectTimer")) {
TimerMgr::instance()->cancel("Dhcp6DbReconnectTimer"); }
// Set network state to service enabled
network_state_.enableService();
// Toss the reconnct control, we're done with it
db_reconnect_ctl_.reset();
} else {
if (!db_reconnect_ctl_->checkRetries()) {
LOG_ERROR(dhcp6_logger, DHCP6_DB_RECONNECT_RETRIES_EXHAUSTED)
.arg(db_reconnect_ctl_->maxRetries());
shutdown();
return;
}
LOG_INFO(dhcp6_logger, DHCP6_DB_RECONNECT_ATTEMPT_SCHEDULE)
.arg(db_reconnect_ctl_->maxRetries() - db_reconnect_ctl_->retriesLeft() + 1)
.arg(db_reconnect_ctl_->maxRetries())
.arg(db_reconnect_ctl_->retryInterval());
if (!TimerMgr::instance()->isTimerRegistered("Dhcp6DbReconnectTimer")) {
TimerMgr::instance()->registerTimer("Dhcp6DbReconnectTimer",
boost::bind(&ControlledDhcpv6Srv::dbReconnect, this),
db_reconnect_ctl_->retryInterval() * 1000,
asiolink::IntervalTimer::ONE_SHOT);
}
TimerMgr::instance()->setup("Dhcp6DbReconnectTimer");
}
}
bool
ControlledDhcpv6Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
// Disable service until we recover
network_state_.disableService();
if (!db_reconnect_ctl) {
// This shouldn't never happen
LOG_ERROR(dhcp6_logger, DHCP6_DB_RECONNECT_NO_DB_CTL);
return (false);
}
// If reconnect isn't enabled, log it and return false
if (!db_reconnect_ctl->retriesLeft() ||
!db_reconnect_ctl->retryInterval()) {
LOG_INFO(dhcp6_logger, DHCP6_DB_RECONNECT_DISABLED)
.arg(db_reconnect_ctl->retriesLeft())
.arg(db_reconnect_ctl->retryInterval());
return(false);
}
// Save the reconnect control
db_reconnect_ctl_ = db_reconnect_ctl;
// Invoke reconnect method
dbReconnect();
return(true);
}
}; // end of isc::dhcp namespace
}; // end of isc namespace
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -11,6 +11,7 @@
#include <asiolink/asiolink.h>
#include <cc/data.h>
#include <cc/command_interpreter.h>
#include <dhcpsrv/database_connection.h>
#include <dhcpsrv/timer_mgr.h>
#include <dhcp6/dhcp6_srv.h>
......@@ -317,6 +318,12 @@ private:
/// deleted.
void deleteExpiredReclaimedLeases(const uint32_t secs);
/// @brief Attempts to reconnect the server to the DB backend managers
void dbReconnect();
/// @brief Callback DB backends should invoke upon loss of connectivity
bool dbLostCallback(ReconnectCtlPtr db_reconnect_ctl);
/// @brief Static pointer to the sole instance of the DHCP server.
///
/// This is required for config and command handlers to gain access to
......@@ -332,6 +339,8 @@ private:
/// make sure that the @c TimerMgr outlives instance of this class.
TimerMgrPtr timer_mgr_;
/// @brief Pointer the current DB reconnect control values
ReconnectCtlPtr db_reconnect_ctl_;
};
}; // namespace isc::dhcp
......
This diff is collapsed.
......@@ -605,6 +605,26 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"max-reconnect-tries\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp6Parser::make_MAX_RECONNECT_TRIES(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("max-reconnect-tries", driver.loc_);
}
}
\"reconnect-wait-time\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
return isc::dhcp::Dhcp6Parser::make_RECONNECT_WAIT_TIME(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("reconnect-wait-time", driver.loc_);
}
}
\"preferred-lifetime\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
......
......@@ -100,6 +100,33 @@ This informational message is printed every time the IPv6 DHCP server
is started. It indicates what database backend type is being to store
lease and other information.
% DHCP6_DB_RECONNECT_ATTEMPT_SCHEDULE Scheduling attempt %1 of %2 in %3 seconds
An informational message indicating that the server is scheduling the next
attempt to reconnect to its lease and/or host databases. This occurs when the
server has lost databse connectivity and is attempting to reconnect
automatically.
% DHCP6_DB_RECONNECT_ATTEMPT_FAILED database reconnect failed: %1
An error message indicating that an attempt to reconnect to the lease and/or
host data bases has failed. This occurs after connectivity to either one
has been lost and an automatic attempt to reconnect has failed.
% DHCP6_DB_RECONNECT_NO_DB_CTL unexpected error in database reconnect
This is an error message indicating a programmatic error that should not
occur. It will prohibit the server from attempting to reconnect to its
databases if connectivy is lost, and the server will exit. This error
should be reported.
% DHCP6_DB_RECONNECT_DISABLED database reconnect is disabled: max-reconnect-tries %1, reconnect-wait-time %1
This is an informational message indicating that connetivity to either the
lease or host database or both and that automatic reconnect is not enabled.
% DHCP6_DB_RECONNECT_RETRIES_EXHAUSTED - Maximum number of Database reconnect attempts: %1, has been exhausted without success, server is shutting down!
This error indicates that the server is shutting after failing to reconnect to
the lease and/or host database(s) after making the maximum configured number
of reconnect attempts. Loss of connectivity is typically a network or database
server issue.
% DHCP6_DDNS_CREATE_ADD_NAME_CHANGE_REQUEST created name change request: %1
This debug message is logged when the new Name Change Request has been created
to perform the DNS Update, which adds new RRs.
......
This diff is collapsed.
......@@ -374,133 +374,135 @@ namespace isc { namespace dhcp {
TOKEN_READONLY = 282,
TOKEN_CONNECT_TIMEOUT = 283,
TOKEN_CONTACT_POINTS = 284,
TOKEN_KEYSPACE = 285,
TOKEN_PREFERRED_LIFETIME = 286,
TOKEN_VALID_LIFETIME = 287,
TOKEN_RENEW_TIMER = 288,
TOKEN_REBIND_TIMER = 289,
TOKEN_DECLINE_PROBATION_PERIOD = 290,
TOKEN_SUBNET6 = 291,
TOKEN_OPTION_DEF = 292,
TOKEN_OPTION_DATA = 293,
TOKEN_NAME = 294,
TOKEN_DATA = 295,
TOKEN_CODE = 296,
TOKEN_SPACE = 297,
TOKEN_CSV_FORMAT = 298,
TOKEN_ALWAYS_SEND = 299,
TOKEN_RECORD_TYPES = 300,
TOKEN_ENCAPSULATE = 301,
TOKEN_ARRAY = 302,
TOKEN_POOLS = 303,
TOKEN_POOL = 304,
TOKEN_PD_POOLS = 305,
TOKEN_PREFIX = 306,
TOKEN_PREFIX_LEN = 307,
TOKEN_EXCLUDED_PREFIX = 308,
TOKEN_EXCLUDED_PREFIX_LEN = 309,
TOKEN_DELEGATED_LEN = 310,
TOKEN_USER_CONTEXT = 311,
TOKEN_COMMENT = 312,
TOKEN_SUBNET = 313,
TOKEN_INTERFACE = 314,
TOKEN_INTERFACE_ID = 315,
TOKEN_ID = 316,
TOKEN_RAPID_COMMIT = 317,
TOKEN_RESERVATION_MODE = 318,
TOKEN_DISABLED = 319,
TOKEN_OUT_OF_POOL = 320,
TOKEN_ALL = 321,
TOKEN_SHARED_NETWORKS = 322,
TOKEN_MAC_SOURCES = 323,
TOKEN_RELAY_SUPPLIED_OPTIONS = 324,
TOKEN_HOST_RESERVATION_IDENTIFIERS = 325,
TOKEN_CLIENT_CLASSES = 326,
TOKEN_TEST = 327,
TOKEN_CLIENT_CLASS = 328,
TOKEN_RESERVATIONS = 329,
TOKEN_IP_ADDRESSES = 330,
TOKEN_PREFIXES = 331,
TOKEN_DUID = 332,
TOKEN_HW_ADDRESS = 333,
TOKEN_HOSTNAME = 334,
TOKEN_FLEX_ID = 335,
TOKEN_RELAY = 336,
TOKEN_IP_ADDRESS = 337,
TOKEN_HOOKS_LIBRARIES = 338,
TOKEN_LIBRARY = 339,
TOKEN_PARAMETERS = 340,
TOKEN_EXPIRED_LEASES_PROCESSING = 341,
TOKEN_RECLAIM_TIMER_WAIT_TIME = 342,
TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 343,
TOKEN_HOLD_RECLAIMED_TIME = 344,
TOKEN_MAX_RECLAIM_LEASES = 345,
TOKEN_MAX_RECLAIM_TIME = 346,
TOKEN_UNWARNED_RECLAIM_CYCLES = 347,
TOKEN_SERVER_ID = 348,
TOKEN_LLT = 349,
TOKEN_EN = 350,
TOKEN_LL = 351,
TOKEN_IDENTIFIER = 352,
TOKEN_HTYPE = 353,
TOKEN_TIME = 354,
TOKEN_ENTERPRISE_ID = 355,
TOKEN_DHCP4O6_PORT = 356,
TOKEN_CONTROL_SOCKET = 357,
TOKEN_SOCKET_TYPE = 358,
TOKEN_SOCKET_NAME = 359,
TOKEN_DHCP_DDNS = 360,
TOKEN_ENABLE_UPDATES = 361,
TOKEN_QUALIFYING_SUFFIX = 362,
TOKEN_SERVER_IP = 363,
TOKEN_SERVER_PORT = 364,
TOKEN_SENDER_IP = 365,
TOKEN_SENDER_PORT = 366,
TOKEN_MAX_QUEUE_SIZE = 367,
TOKEN_NCR_PROTOCOL = 368,
TOKEN_NCR_FORMAT = 369,
TOKEN_ALWAYS_INCLUDE_FQDN = 370,
TOKEN_OVERRIDE_NO_UPDATE = 371,
TOKEN_OVERRIDE_CLIENT_UPDATE = 372,
TOKEN_REPLACE_CLIENT_NAME = 373,
TOKEN_GENERATED_PREFIX = 374,
TOKEN_UDP = 375,
TOKEN_TCP = 376,
TOKEN_JSON = 377,
TOKEN_WHEN_PRESENT = 378,
TOKEN_NEVER = 379,
TOKEN_ALWAYS = 380,
TOKEN_WHEN_NOT_PRESENT = 381,
TOKEN_LOGGING = 382,
TOKEN_LOGGERS = 383,
TOKEN_OUTPUT_OPTIONS = 384,
TOKEN_OUTPUT = 385,
TOKEN_DEBUGLEVEL = 386,
TOKEN_SEVERITY = 387,
TOKEN_FLUSH = 388,
TOKEN_MAXSIZE = 389,
TOKEN_MAXVER = 390,
TOKEN_DHCP4 = 391,
TOKEN_DHCPDDNS = 392,
TOKEN_CONTROL_AGENT = 393,
TOKEN_TOPLEVEL_JSON = 394,
TOKEN_TOPLEVEL_DHCP6 = 395,
TOKEN_SUB_DHCP6 = 396,
TOKEN_SUB_INTERFACES6 = 397,
TOKEN_SUB_SUBNET6 = 398,
TOKEN_SUB_POOL6 = 399,
TOKEN_SUB_PD_POOL = 400,
TOKEN_SUB_RESERVATION = 401,
TOKEN_SUB_OPTION_DEFS = 402,
TOKEN_SUB_OPTION_DEF = 403,
TOKEN_SUB_OPTION_DATA = 404,
TOKEN_SUB_HOOKS_LIBRARY = 405,
TOKEN_SUB_DHCP_DDNS = 406,
TOKEN_SUB_LOGGING = 407,
TOKEN_STRING = 408,
TOKEN_INTEGER = 409,
TOKEN_FLOAT = 410,
TOKEN_BOOLEAN = 411
TOKEN_MAX_RECONNECT_TRIES = 285,
TOKEN_RECONNECT_WAIT_TIME = 286,
TOKEN_KEYSPACE = 287,
TOKEN_PREFERRED_LIFETIME = 288,
TOKEN_VALID_LIFETIME = 289,
TOKEN_RENEW_TIMER = 290,
TOKEN_REBIND_TIMER = 291,
TOKEN_DECLINE_PROBATION_PERIOD = 292,
TOKEN_SUBNET6 = 293,
TOKEN_OPTION_DEF = 294,
TOKEN_OPTION_DATA = 295,
TOKEN_NAME = 296,
TOKEN_DATA = 297,
TOKEN_CODE = 298,
TOKEN_SPACE = 299,
TOKEN_CSV_FORMAT = 300,
TOKEN_ALWAYS_SEND = 301,
TOKEN_RECORD_TYPES = 302,
TOKEN_ENCAPSULATE = 303,
TOKEN_ARRAY = 304,
TOKEN_POOLS = 305,
TOKEN_POOL = 306,
TOKEN_PD_POOLS = 307,
TOKEN_PREFIX = 308,
TOKEN_PREFIX_LEN = 309,
TOKEN_EXCLUDED_PREFIX = 310,
TOKEN_EXCLUDED_PREFIX_LEN = 311,
TOKEN_DELEGATED_LEN = 312,
TOKEN_USER_CONTEXT = 313,
TOKEN_COMMENT = 314,
TOKEN_SUBNET = 315,
TOKEN_INTERFACE = 316,
TOKEN_INTERFACE_ID = 317,
TOKEN_ID = 318,
TOKEN_RAPID_COMMIT = 319,
TOKEN_RESERVATION_MODE = 320,
TOKEN_DISABLED = 321,
TOKEN_OUT_OF_POOL = 322,
TOKEN_ALL = 323,
TOKEN_SHARED_NETWORKS = 324,
TOKEN_MAC_SOURCES = 325,
TOKEN_RELAY_SUPPLIED_OPTIONS = 326,