Commit 9a7cd6e0 authored by Thomas Markwalder's avatar Thomas Markwalder

[#365,!194] kea-dhcp4 can be configured to calculate T1 and T2

doc/guide/dhcp4-srv.xml
    Updated user guide with new parameters and details on rules

src/lib/cc/data.cc
    DoubleElement::toJSON(std::ostream& ss) - modified to ensure whole number
     values are suffixed with ".0"

src/lib/utils/doubles.h - new file
   provides a function for equating doubles within a given tolerance

src/lib/cc/simple_parser.*
    SimpleParser::getDouble() - new method for fetching real number
    parameters as DoulbeElements

src/lib/dhcpsrv/network.*
    Added members and support for new paramters to Network4:
        calculate_tee_times_, t1_percent_, t2_percent_

src/lib/dhcpsrv/parsers/dhcp_parsers.cc
src/lib/dhcpsrv/parsers/simple_parser4.cc
    Added support for new parameters to Subnet4ConfigParser

src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp4/json_config_parser.cc
    Added parser support for calculate-tee-times, t1-percent, and t2-percent

src/bin/dhcp4/dhcp4_srv.*
    Dhcpv4Srv::setTeeTimes(lease, subnet, resp) - new method for
    determining T1 adn T2 values
parent 5498f4ff
<!--
- Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
- Copyright (C) 2014-2019 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
......@@ -231,16 +231,11 @@ defines how long the addresses (leases) given out by the
server are valid. If nothing changes, a client that got an address is allowed to
use it for 4000 seconds. (Note that integer numbers are specified as is,
without any quotes around them.) <command>renew-timer</command> and
<command>rebind-timer</command> are values (also in seconds) that
define T1 and T2 timers that govern when the client will begin the renewal and
rebind procedures. <note> Both <command>renew-timer</command> and
<command>rebind-timer</command> are optional. The server will only send
rebind-timer to the client, via DHPv4 option code 59, if it is less than
valid-lifetime; and it will only send renew-timer, via DHCPv4 option code 58,
if it is less than rebind-timer (or valid-lifetime if rebind-timer was not
specified). In their absence, the client should select values for T1 and T2
timers according to the <link xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="http://tools.ietf.org/html/rfc2131">RFC 2131</link>.</note></para>
<command>rebind-timer</command> are values (also in seconds) that may be
used to define T1 and T2 timers that govern when the client will begin the renewal
and rebind procedures. Please see this section:<xref linkend="dhcp4-std-options-list"/>
for more details on generating T1 and T2.
</para>
<para>The <command>interfaces-config</command> map specifies the server
configuration concerning the network interfaces, on which the server should
......@@ -1141,10 +1136,73 @@ temporarily override a list of interface names and listen on all interfaces.
address) and the last (typically broadcast address) address from that pool.
In the aforementioned example of pool 192.0.3.0/24, both 192.0.3.0 and
192.0.3.255 addresses may be assigned as well. This may be invalid in some
network configurations. If you want to avoid this, please use the "min-max" notation.
network configurations. If you want to avoid this, please use the "min-max"
notation.
</para>
</section>
<section xml:id="dhcp4-t1-t2-times">
<title>Sending T1 (Option 58) and T2 (Option 59)</title>
According to <link xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="http://tools.ietf.org/html/rfc2131">RFC 2131</link>,
servers should send values for T1 and T2 that are 50% and 87.5%
of the lease life time, repsectively. By default, kea-dhcp4 does
not send either value. It can be configured to send values that
are specified explicitly or that are calculated as percentages of
the lease time. The server's behavior is governed by combination of
configuration parameters, two of which have already been mentioned.
<para>
To send specific, fixed values use the following two parameters:
<itemizedlist>
<listitem>
<simpara><command>renew-timer</command> - specifies the value of T1 in
seconds.
</simpara>
</listitem>
<listitem>
<simpara><command>rebind-timer</command> - specifies the value of T2 in
seconds.
</simpara>
</listitem>
</itemizedlist>
The server will only send T2 if it is less than valid lease time. T1 will
only be sent if a: T2 is being sent and T1 is less than T2 or b: T2 is not being
sent and T1 is less than the valid lease time.
</para>
<para>
Calculating the values is controlled by the following three parameters.
<itemizedlist>
<listitem>
<simpara>
<command>calculate-tee-times</command> - when true, T1 and T2 will be
calculated as percentages of the valid lease time. It defaults to false.
</simpara>
</listitem>
<listitem>
<simpara>
<command>t1-percent</command> - the percentage of the valid lease time to
use for T1. It is expressed as a real number between 0.0 and 1.0 and must
be less than t2-percent. The default value is 0.50 per RFC 2131.
</simpara>
</listitem>
<listitem>
<simpara>
<command>t2-percent</command> - the percentage of the valid lease time to
use for T2. It is expressed as a real number between 0.0 and 1.0 and must
be greater than t1-percent. The default value is .875 per RFC 2131.
</simpara>
</listitem>
</itemizedlist>
</para>
<note>
In the event that both explicit values are specified and calculate-tee-times
is true, the server will use the explicit values. If you plan on having a
mixture where some subnets or share-networks will use explicit values and some
will use calculated values you must not define the explicit values at any level
higher than where they will be used. Inheriting them from too high of a scope,
such as global, will cause them to have values at every level underneath (shared-
networks and subnets), effectively disabling calculated values.
</note>
</section>
<section xml:id="dhcp4-std-options">
<title>Standard DHCPv4 Options</title>
<para>
......
#line 1 "d2_lexer.cc"
#line 2 "d2_lexer.cc"
#line 3 "d2_lexer.cc"
#line 4 "d2_lexer.cc"
#define YY_INT_ALIGNED short int
......@@ -1146,7 +1146,7 @@ unsigned int comment_start_line = 0;
/* To avoid the call to exit... oops! */
#define YY_FATAL_ERROR(msg) isc::d2::D2ParserContext::fatal(msg)
#line 1149 "d2_lexer.cc"
#line 1150 "d2_lexer.cc"
/* noyywrap disables automatic rewinding for the next file to parse. Since we
always parse only a single string, there's no need to do any wraps. And
using yywrap requires linking with -lfl, which provides the default yywrap
......@@ -1172,8 +1172,8 @@ unsigned int comment_start_line = 0;
by moving it ahead by yyleng bytes. yyleng specifies the length of the
currently matched token. */
#define YY_USER_ACTION driver.loc_.columns(yyleng);
#line 1175 "d2_lexer.cc"
#line 1176 "d2_lexer.cc"
#line 1177 "d2_lexer.cc"
#define INITIAL 0
#define COMMENT 1
......@@ -1491,7 +1491,7 @@ YY_DECL
}
#line 1494 "d2_lexer.cc"
#line 1495 "d2_lexer.cc"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
......@@ -2393,7 +2393,7 @@ YY_RULE_SETUP
#line 738 "d2_lexer.ll"
ECHO;
YY_BREAK
#line 2396 "d2_lexer.cc"
#line 2397 "d2_lexer.cc"
case YY_END_OF_BUFFER:
{
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/* Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
/* Copyright (C) 2016-2019 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
......@@ -841,6 +841,40 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"calculate-tee-times\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
case isc::dhcp::Parser4Context::SUBNET4:
case isc::dhcp::Parser4Context::SHARED_NETWORK:
return isc::dhcp::Dhcp4Parser::make_CALCULATE_TEE_TIMES(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("calculate-tee-times", driver.loc_);
}
}
\"t1-percent\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
case isc::dhcp::Parser4Context::SUBNET4:
case isc::dhcp::Parser4Context::SHARED_NETWORK:
return isc::dhcp::Dhcp4Parser::make_T1_PERCENT(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("t1-percent", driver.loc_);
}
}
\"t2-percent\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
case isc::dhcp::Parser4Context::SUBNET4:
case isc::dhcp::Parser4Context::SHARED_NETWORK:
return isc::dhcp::Dhcp4Parser::make_T2_PERCENT(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("t2-percent", driver.loc_);
}
}
\"Logging\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::CONFIG:
......
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
/* Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
/* Copyright (C) 2016-2019 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
......@@ -116,6 +116,9 @@ using namespace std;
RECORD_TYPES "record-types"
ENCAPSULATE "encapsulate"
ARRAY "array"
CALCULATE_TEE_TIMES "calculate-tee-times"
T1_PERCENT "t1-percent"
T2_PERCENT "t2-percent"
SHARED_NETWORKS "shared-networks"
......@@ -465,6 +468,9 @@ global_param: valid_lifetime
| config_control
| server_tag
| reservation_mode
| calculate_tee_times
| t1_percent
| t2_percent
| unknown_map_entry
;
......@@ -483,6 +489,21 @@ rebind_timer: REBIND_TIMER COLON INTEGER {
ctx.stack_.back()->set("rebind-timer", prf);
};
calculate_tee_times: CALCULATE_TEE_TIMES COLON BOOLEAN {
ElementPtr ctt(new BoolElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("calculate-tee-times", ctt);
};
t1_percent: T1_PERCENT COLON FLOAT {
ElementPtr t1(new DoubleElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("t1-percent", t1);
};
t2_percent: T2_PERCENT COLON FLOAT {
ElementPtr t2(new DoubleElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("t2-percent", t2);
};
decline_probation_period: DECLINE_PROBATION_PERIOD COLON INTEGER {
ElementPtr dpp(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("decline-probation-period", dpp);
......@@ -1060,6 +1081,9 @@ subnet4_param: valid_lifetime
| subnet_4o6_subnet
| user_context
| comment
| calculate_tee_times
| t1_percent
| t2_percent
| unknown_map_entry
;
......@@ -1191,6 +1215,9 @@ shared_network_param: name
| valid_lifetime
| user_context
| comment
| calculate_tee_times
| t1_percent
| t2_percent
| unknown_map_entry
;
......
// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2019 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
......@@ -2190,32 +2190,8 @@ Dhcpv4Srv::assignLease(Dhcpv4Exchange& ex) {
// Subnet mask (type 1)
resp->addOption(getNetmaskOption(subnet));
// rebind timer (type 59) - if specified then send it only it if
// it is less than lease lifetime. Note we "sanity" check T1
// and T2 against lease lifetime here in event the lifetime has
// been altered somewhere along the line.
uint32_t timer_ceiling = lease->valid_lft_;
if ((!subnet->getT2().unspecified()) &&
(subnet->getT2() < timer_ceiling)) {
OptionUint32Ptr t2(new OptionUint32(Option::V4,
DHO_DHCP_REBINDING_TIME,
subnet->getT2()));
resp->addOption(t2);
// If T2 is specified, then it becomes the ceiling for T1
timer_ceiling = subnet->getT2();
}
// renewal-timer (type 58) - if specified then send it only if
// it is less than the ceiling (T2 if given, lease life time if not)
if ((!subnet->getT1().unspecified()) &&
(subnet->getT1() < timer_ceiling)) {
OptionUint32Ptr t1(new OptionUint32(Option::V4,
DHO_DHCP_RENEWAL_TIME,
subnet->getT1()));
resp->addOption(t1);
}
// Set T1 and T2 per configuration.
setTeeTimes(lease, subnet, resp);
// Create NameChangeRequests if DDNS is enabled and this is a
// real allocation.
......@@ -2250,6 +2226,46 @@ Dhcpv4Srv::assignLease(Dhcpv4Exchange& ex) {
}
}
void
Dhcpv4Srv::setTeeTimes(const Lease4Ptr& lease, const Subnet4Ptr& subnet, Pkt4Ptr resp) {
uint32_t t2_time = 0;
// If T2 is explicitly configured we'll use try value.
if (!subnet->getT2().unspecified()) {
t2_time = subnet->getT2();
} else if (subnet->getCalculateTeeTimes()) {
// Calculating tee times is enabled, so calculated it.
t2_time = static_cast<uint32_t>(subnet->getT2Percent() * (lease->valid_lft_));
}
// Send the T2 candidate value only if it's sane: to be sane it must be less than
// the valid life time.
uint32_t timer_ceiling = lease->valid_lft_;
if (t2_time > 0 && t2_time < timer_ceiling) {
OptionUint32Ptr t2(new OptionUint32(Option::V4, DHO_DHCP_REBINDING_TIME, t2_time));
resp->addOption(t2);
// When we send T2, timer ceiling for T1 becomes T2.
timer_ceiling = t2_time;
}
uint32_t t1_time = 0;
// If T1 is explicitly configured we'll use try value.
if (!subnet->getT1().unspecified()) {
t1_time = subnet->getT1();
} else if (subnet->getCalculateTeeTimes()) {
// Calculating tee times is enabled, so calculate it.
t1_time = static_cast<uint32_t>(subnet->getT1Percent() * (lease->valid_lft_));
}
// Send T1 if it's sane: If we sent T2, T1 must be less than that. If not it must be
// less than the valid life time.
if (t1_time > 0 && t1_time < timer_ceiling) {
OptionUint32Ptr t1(new OptionUint32(Option::V4, DHO_DHCP_RENEWAL_TIME, t1_time));
resp->addOption(t1);
}
}
uint16_t
Dhcpv4Srv::checkRelayPort(const Dhcpv4Exchange& ex) {
......
// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2019 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
......@@ -539,6 +539,33 @@ protected:
/// @param ex DHCPv4 exchange holding the client's message to be checked.
void assignLease(Dhcpv4Exchange& ex);
/// @brief Adds the T1 and T2 timers to the outbound response as appropriate
///
/// This method determines if either of the timers T1 (option 58) and T2
/// (option 59) should be sent to the client. It is influenced by the
/// lease's subnet's values for renew-timer, rebind-timer,
/// calculate-tee-times, t1-perecnt, and t2-percent as follows:
///
/// By default neither T1 nor T2 will be sent.
///
/// T2:
///
/// If rebind-timer is set use its value, otherwise if calculate-tee-times
/// is true use the value given by valid lease time * t2-percent. Either
/// way the value will only be sent if it is less than the valid lease time.
///
/// T1:
///
/// If renew-timer is set use its value, otherwise if calculate-tee-times
/// is true use the value given by valid lease time * t1-percent. Either
/// way the value will only be sent if it is less than T2 when T2 is being
/// sent, or less than the valid lease time if T2 is not being sent.
///
/// @param lease lease being assigned to the client
/// @param subnet the subnet to which the lease belongs
/// @param resp outbound response for the client to which timers are added.
void setTeeTimes(const Lease4Ptr& lease, const Subnet4Ptr& subnet, Pkt4Ptr resp);
/// @brief Append basic options if they are not present.
///
/// This function adds the following basic options if they
......
// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2019 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
......@@ -546,7 +546,10 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
(config_pair.first == "server-hostname") ||
(config_pair.first == "boot-file-name") ||
(config_pair.first == "server-tag") ||
(config_pair.first == "reservation-mode")) {
(config_pair.first == "reservation-mode") ||
(config_pair.first == "calculate-tee-times") ||
(config_pair.first == "t1-percent") ||
(config_pair.first == "t2-percent")) {
continue;
}
......
// Generated 201811271343
// A Bison parser, made by GNU Bison 3.2.1.
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++
// Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc.
// Copyright (C) 2002-2015 Free Software Foundation, Inc.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -39,145 +38,12 @@
#ifndef YY_PARSER4_LOCATION_HH_INCLUDED
# define YY_PARSER4_LOCATION_HH_INCLUDED
# include <algorithm> // std::max
# include <iostream>
# include <string>
# include "position.hh"
# ifndef YY_NULLPTR
# if defined __cplusplus
# if 201103L <= __cplusplus
# define YY_NULLPTR nullptr
# else
# define YY_NULLPTR 0
# endif
# else
# define YY_NULLPTR ((void*)0)
# endif
# endif
#line 14 "dhcp4_parser.yy" // location.cc:339
#line 14 "dhcp4_parser.yy" // location.cc:296
namespace isc { namespace dhcp {
#line 60 "location.hh" // location.cc:339
/// A point in a source file.
class position
{
public:
/// Construct a position.
explicit position (std::string* f = YY_NULLPTR,
unsigned l = 1u,
unsigned c = 1u)
: filename (f)
, line (l)
, column (c)
{}
/// Initialization.
void initialize (std::string* fn = YY_NULLPTR,
unsigned l = 1u,
unsigned c = 1u)
{
filename = fn;
line = l;
column = c;
}
/** \name Line and Column related manipulators
** \{ */
/// (line related) Advance to the COUNT next lines.
void lines (int count = 1)
{
if (count)
{
column = 1u;
line = add_ (line, count, 1);
}
}
/// (column related) Advance to the COUNT next columns.
void columns (int count = 1)
{
column = add_ (column, count, 1);
}
/** \} */
/// File name to which this position refers.
std::string* filename;
/// Current line number.
unsigned line;
/// Current column number.
unsigned column;
private:
/// Compute max (min, lhs+rhs).
static unsigned add_ (unsigned lhs, int rhs, int min)
{
return static_cast<unsigned> (std::max (min,
static_cast<int> (lhs) + rhs));
}
};
/// Add \a width columns, in place.
inline position&
operator+= (position& res, int width)
{
res.columns (width);
return res;
}
/// Add \a width columns.
inline position
operator+ (position res, int width)
{
return res += width;
}
/// Subtract \a width columns, in place.
inline position&
operator-= (position& res, int width)
{
return res += -width;
}
/// Subtract \a width columns.
inline position
operator- (position res, int width)
{
return res -= width;
}
/// Compare two position objects.
inline bool
operator== (const position& pos1, const position& pos2)
{
return (pos1.line == pos2.line
&& pos1.column == pos2.column
&& (pos1.filename == pos2.filename
|| (pos1.filename && pos2.filename
&& *pos1.filename == *pos2.filename)));
}
/// Compare two position objects.
inline bool
operator!= (const position& pos1, const position& pos2)
{
return !(pos1 == pos2);
}
/** \brief Intercept output stream redirection.
** \param ostr the destination output stream
** \param pos a reference to the position to redirect
*/
template <typename YYChar>
std::basic_ostream<YYChar>&
operator<< (std::basic_ostream<YYChar>& ostr, const position& pos)
{
if (pos.filename)
ostr << *pos.filename << ':';
return ostr << pos.line << '.' << pos.column;
}
/// Two points in a source file.
#line 46 "location.hh" // location.cc:296
/// Abstract a location.
class location
{
public:
......@@ -186,27 +52,30 @@ namespace isc { namespace dhcp {
location (const position& b, const position& e)
: begin (b)
, end (e)
{}
{
}
/// Construct a 0-width location in \a p.
explicit location (const position& p = position ())
: begin (p)
, end (p)
{}
{
}
/// Construct a 0-width location in \a f, \a l, \a c.
explicit location (std::string* f,
unsigned l = 1u,
unsigned c = 1u)
unsigned int l = 1u,
unsigned int c = 1u)
: begin (f, l, c)
, end (f, l, c)
{}
{
}
/// Initialization.
void initialize (std::string* f = YY_NULLPTR,
unsigned l = 1u,
unsigned c = 1u)
unsigned int l = 1u,
unsigned int c = 1u)
{
begin.initialize (f, l, c);
end = begin;
......@@ -301,10 +170,10 @@ namespace isc { namespace dhcp {
** Avoid duplicate information.
*/
template <typename YYChar>
std::basic_ostream<YYChar>&
inline std::basic_ostream<YYChar>&
operator<< (std::basic_ostream<YYChar>& ostr, const location& loc)
{
unsigned end_col = 0 < loc.end.column ? loc.end.column - 1 : 0;
unsigned int end_col = 0 < loc.end.column ? loc.end.column - 1 : 0;
ostr << loc.begin;
if (loc.end.filename
&& (!loc.begin.filename
......@@ -317,7 +186,7 @@ namespace isc { namespace dhcp {
return ostr;
}
#line 14 "dhcp4_parser.yy" // location.cc:339
#line 14 "dhcp4_parser.yy" // location.cc:296
} } // isc::dhcp
#line 322 "location.hh" // location.cc:339
#line 192 "location.hh" // location.cc:296
#endif // !YY_PARSER4_LOCATION_HH_INCLUDED
// Generated 201811271343
// A Bison parser, made by GNU Bison 3.2.1.
// Starting with Bison 3.2, this file is useless: the structure it
// used to define is now defined in "location.hh".
//
// To get rid of this file:
// 1. add 'require "3.2"' (or newer) to your grammar file
// 2. remove references to this file from your build system
// 3. if you used to include it, include "location.hh" instead.
#include "location.hh"
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++
// Copyright (C) 2002-2015 Free Software Foundation, Inc.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// As a special exception, you may create a larger work that contains
// part or all of the Bison parser skeleton and distribute that work
// under terms of your choice, so long as that work isn't itself a
// parser generator using the skeleton or a modified version thereof
// as a parser skeleton. Alternatively, if you modify or redistribute
// the parser skeleton itself, you may (at your option) remove this
// special exception, which will cause the skeleton and the resulting
// Bison output files to be licensed under the GNU General Public
// License without this special exception.
// This special exception was added by the Free Software Foundation in
// version 2.2 of Bison.
/**
** \file position.hh
** Define the isc::dhcp::position class.
*/
#ifndef YY_PARSER4_POSITION_HH_INCLUDED
# define YY_PARSER4_POSITION_HH_INCLUDED
# include <algorithm> // std::max
# include <iostream>
# include <string>
# ifndef YY_NULLPTR
# if defined __cplusplus && 201103L <= __cplusplus
# define YY_NULLPTR nullptr
# else
# define YY_NULLPTR 0
# endif
# endif
#line 14 "dhcp4_parser.yy" // location.cc:296
namespace isc { namespace dhcp {
#line 56 "position.hh" // location.cc:296
/// Abstract a position.
class position
{
public:
/// Construct a position.
explicit position (std::string* f = YY_NULLPTR,
unsigned int l = 1u,
unsigned int c = 1u)
: filename (f)
, line (l)
, column (c)
{
}
/// Initialization.
void initialize (std::string* fn = YY_NULLPTR,
unsigned int l = 1u,
unsigned int c = 1u)
{
filename = fn;
line = l;
column = c;
}
/** \name Line and Column related manipulators
** \{ */
/// (line related) Advance to the COUNT next lines.
void lines (int count = 1)
{
if (count)
{
column = 1u;
line = add_ (line, count, 1);
}
}
/// (column related) Advance to the COUNT next columns.
void columns (int count = 1)
{
column = add_ (column, count, 1);
}
/** \} */