mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 13:37:55 +00:00
[#969] DHCPv6 allocators configurable
This commit is contained in:
parent
9571b8f80b
commit
d92cc17a20
@ -11,6 +11,14 @@
|
||||
{
|
||||
// Kea DHCPv6 server configuration begins here.
|
||||
"Dhcp6": {
|
||||
// Global flag selecting an IP address allocation strategy for all
|
||||
// subnets.
|
||||
"allocator": "iterative",
|
||||
|
||||
// Global flag selecting a delegated prefix allocation strategy
|
||||
// for all subnets.
|
||||
"pd-allocator": "random",
|
||||
|
||||
// Ordered list of client classes used by the DHCPv6 server.
|
||||
"client-classes": [
|
||||
{
|
||||
@ -650,6 +658,14 @@
|
||||
// networks group subnets together.
|
||||
"shared-networks": [
|
||||
{
|
||||
// A flag selecting an IP address allocation strategy for all
|
||||
// subnets in this shared network.
|
||||
"allocator": "random",
|
||||
|
||||
// A flag selecting a delegated prefix allocation strategy for
|
||||
// all subnets in this shared network.
|
||||
"pd-allocator": "iterative",
|
||||
|
||||
// Restricts this shared network to allow only clients
|
||||
// that belong to the particular client class. If an
|
||||
// empty string is provided, no restriction is applied.
|
||||
@ -773,6 +789,14 @@
|
||||
// List of IPv6 subnets belonging to this shared network.
|
||||
"subnet6": [
|
||||
{
|
||||
// A flag selecting an IP address allocation strategy for
|
||||
// the subnet.
|
||||
"allocator": "iterative",
|
||||
|
||||
// A flag selecting a delegated prefix allocation strategy
|
||||
// for the subnet.
|
||||
"pd-allocator": "iterative",
|
||||
|
||||
// Restricts this subnet to allow only clients that belong
|
||||
// to the particular client class. If an empty string is
|
||||
// provided, no restriction is applied.
|
||||
|
@ -1,4 +1,4 @@
|
||||
// A Bison parser, made by GNU Bison 3.7.6.
|
||||
// A Bison parser, made by GNU Bison 3.8.2.
|
||||
|
||||
// Skeleton implementation for Bison LALR(1) parsers in C++
|
||||
|
||||
@ -160,9 +160,9 @@ namespace isc { namespace dhcp {
|
||||
Dhcp4Parser::syntax_error::~syntax_error () YY_NOEXCEPT YY_NOTHROW
|
||||
{}
|
||||
|
||||
/*---------------.
|
||||
| symbol kinds. |
|
||||
`---------------*/
|
||||
/*---------.
|
||||
| symbol. |
|
||||
`---------*/
|
||||
|
||||
|
||||
|
||||
@ -507,7 +507,7 @@ namespace isc { namespace dhcp {
|
||||
}
|
||||
|
||||
void
|
||||
Dhcp4Parser::yypop_ (int n)
|
||||
Dhcp4Parser::yypop_ (int n) YY_NOEXCEPT
|
||||
{
|
||||
yystack_.pop (n);
|
||||
}
|
||||
@ -550,13 +550,13 @@ namespace isc { namespace dhcp {
|
||||
}
|
||||
|
||||
bool
|
||||
Dhcp4Parser::yy_pact_value_is_default_ (int yyvalue)
|
||||
Dhcp4Parser::yy_pact_value_is_default_ (int yyvalue) YY_NOEXCEPT
|
||||
{
|
||||
return yyvalue == yypact_ninf_;
|
||||
}
|
||||
|
||||
bool
|
||||
Dhcp4Parser::yy_table_value_is_error_ (int yyvalue)
|
||||
Dhcp4Parser::yy_table_value_is_error_ (int yyvalue) YY_NOEXCEPT
|
||||
{
|
||||
return yyvalue == yytable_ninf_;
|
||||
}
|
||||
@ -4865,16 +4865,16 @@ namespace isc { namespace dhcp {
|
||||
// Actual number of expected tokens
|
||||
int yycount = 0;
|
||||
|
||||
int yyn = yypact_[+yyparser_.yystack_[0].state];
|
||||
const int yyn = yypact_[+yyparser_.yystack_[0].state];
|
||||
if (!yy_pact_value_is_default_ (yyn))
|
||||
{
|
||||
/* Start YYX at -YYN if negative to avoid negative indexes in
|
||||
YYCHECK. In other words, skip the first -YYN actions for
|
||||
this state because they are default actions. */
|
||||
int yyxbegin = yyn < 0 ? -yyn : 0;
|
||||
const int yyxbegin = yyn < 0 ? -yyn : 0;
|
||||
// Stay within bounds of both yycheck and yytname.
|
||||
int yychecklim = yylast_ - yyn + 1;
|
||||
int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
|
||||
const int yychecklim = yylast_ - yyn + 1;
|
||||
const int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
|
||||
for (int yyx = yyxbegin; yyx < yyxend; ++yyx)
|
||||
if (yycheck_[yyx + yyn] == yyx && yyx != symbol_kind::S_YYerror
|
||||
&& !yy_table_value_is_error_ (yytable_[yyx + yyn]))
|
||||
@ -4895,6 +4895,9 @@ namespace isc { namespace dhcp {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
Dhcp4Parser::yy_syntax_error_arguments_ (const context& yyctx,
|
||||
symbol_kind_type yyarg[], int yyargn) const
|
||||
@ -5141,9 +5144,9 @@ namespace isc { namespace dhcp {
|
||||
199, 203, 0, 0, 0, 0, 194, 0, 182, 185,
|
||||
186, 187, 188, 189, 190, 191, 192, 193, 420, 422,
|
||||
424, 568, 418, 426, 0, 430, 428, 650, 417, 372,
|
||||
373, 374, 375, 376, 400, 401, 402, 403, 404, 415,
|
||||
373, 374, 375, 376, 400, 401, 402, 403, 404, 416,
|
||||
390, 391, 405, 406, 407, 408, 409, 410, 411, 412,
|
||||
413, 414, 416, 0, 369, 379, 395, 396, 397, 380,
|
||||
413, 414, 415, 0, 369, 379, 395, 396, 397, 380,
|
||||
382, 383, 386, 387, 388, 385, 381, 377, 378, 398,
|
||||
399, 384, 392, 393, 394, 389, 589, 588, 584, 585,
|
||||
583, 0, 579, 582, 586, 587, 648, 636, 638, 642,
|
||||
@ -5224,9 +5227,9 @@ namespace isc { namespace dhcp {
|
||||
216, 0, 0, 0, 0, 268, 271, 272, 273, 274,
|
||||
275, 276, 0, 282, 0, 0, 0, 0, 236, 0,
|
||||
231, 0, 363, 0, 502, 0, 541, 494, 472, 473,
|
||||
474, 457, 458, 477, 478, 479, 480, 481, 492, 460,
|
||||
474, 457, 458, 477, 478, 479, 480, 481, 493, 460,
|
||||
461, 482, 483, 484, 485, 486, 487, 488, 489, 490,
|
||||
491, 493, 454, 455, 456, 470, 471, 467, 468, 469,
|
||||
491, 492, 454, 455, 456, 470, 471, 467, 468, 469,
|
||||
466, 0, 451, 459, 475, 476, 462, 463, 464, 465,
|
||||
447, 294, 682, 684, 0, 677, 678, 679, 680, 681,
|
||||
670, 671, 675, 676, 672, 673, 674, 0, 662, 663,
|
||||
@ -6265,7 +6268,7 @@ namespace isc { namespace dhcp {
|
||||
|
||||
#line 14 "dhcp4_parser.yy"
|
||||
} } // isc::dhcp
|
||||
#line 6269 "dhcp4_parser.cc"
|
||||
#line 6272 "dhcp4_parser.cc"
|
||||
|
||||
#line 2912 "dhcp4_parser.yy"
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// A Bison parser, made by GNU Bison 3.7.6.
|
||||
// A Bison parser, made by GNU Bison 3.8.2.
|
||||
|
||||
// Skeleton interface for Bison LALR(1) parsers in C++
|
||||
|
||||
@ -133,12 +133,18 @@ using namespace std;
|
||||
# define YY_USE(E) /* empty */
|
||||
#endif
|
||||
|
||||
#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
|
||||
/* Suppress an incorrect diagnostic about yylval being uninitialized. */
|
||||
# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
|
||||
#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__
|
||||
# if __GNUC__ * 100 + __GNUC_MINOR__ < 407
|
||||
# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
|
||||
_Pragma ("GCC diagnostic push") \
|
||||
_Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")
|
||||
# else
|
||||
# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
|
||||
_Pragma ("GCC diagnostic push") \
|
||||
_Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
|
||||
_Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
|
||||
# endif
|
||||
# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
|
||||
_Pragma ("GCC diagnostic pop")
|
||||
#else
|
||||
@ -200,7 +206,7 @@ using namespace std;
|
||||
|
||||
#line 14 "dhcp4_parser.yy"
|
||||
namespace isc { namespace dhcp {
|
||||
#line 204 "dhcp4_parser.h"
|
||||
#line 210 "dhcp4_parser.h"
|
||||
|
||||
|
||||
|
||||
@ -209,27 +215,32 @@ namespace isc { namespace dhcp {
|
||||
class Dhcp4Parser
|
||||
{
|
||||
public:
|
||||
#ifndef PARSER4_STYPE
|
||||
#ifdef PARSER4_STYPE
|
||||
# ifdef __GNUC__
|
||||
# pragma GCC message "bison: do not #define PARSER4_STYPE in C++, use %define api.value.type"
|
||||
# endif
|
||||
typedef PARSER4_STYPE value_type;
|
||||
#else
|
||||
/// A buffer to store and retrieve objects.
|
||||
///
|
||||
/// Sort of a variant, but does not keep track of the nature
|
||||
/// of the stored data, since that knowledge is available
|
||||
/// via the current parser state.
|
||||
class semantic_type
|
||||
class value_type
|
||||
{
|
||||
public:
|
||||
/// Type of *this.
|
||||
typedef semantic_type self_type;
|
||||
typedef value_type self_type;
|
||||
|
||||
/// Empty construction.
|
||||
semantic_type () YY_NOEXCEPT
|
||||
: yybuffer_ ()
|
||||
value_type () YY_NOEXCEPT
|
||||
: yyraw_ ()
|
||||
, yytypeid_ (YY_NULLPTR)
|
||||
{}
|
||||
|
||||
/// Construct and fill.
|
||||
template <typename T>
|
||||
semantic_type (YY_RVREF (T) t)
|
||||
value_type (YY_RVREF (T) t)
|
||||
: yytypeid_ (&typeid (T))
|
||||
{
|
||||
PARSER4__ASSERT (sizeof (T) <= size);
|
||||
@ -238,13 +249,13 @@ namespace isc { namespace dhcp {
|
||||
|
||||
#if 201103L <= YY_CPLUSPLUS
|
||||
/// Non copyable.
|
||||
semantic_type (const self_type&) = delete;
|
||||
value_type (const self_type&) = delete;
|
||||
/// Non copyable.
|
||||
self_type& operator= (const self_type&) = delete;
|
||||
#endif
|
||||
|
||||
/// Destruction, allowed only if empty.
|
||||
~semantic_type () YY_NOEXCEPT
|
||||
~value_type () YY_NOEXCEPT
|
||||
{
|
||||
PARSER4__ASSERT (!yytypeid_);
|
||||
}
|
||||
@ -388,7 +399,7 @@ namespace isc { namespace dhcp {
|
||||
private:
|
||||
#if YY_CPLUSPLUS < 201103L
|
||||
/// Non copyable.
|
||||
semantic_type (const self_type&);
|
||||
value_type (const self_type&);
|
||||
/// Non copyable.
|
||||
self_type& operator= (const self_type&);
|
||||
#endif
|
||||
@ -398,7 +409,7 @@ namespace isc { namespace dhcp {
|
||||
T*
|
||||
yyas_ () YY_NOEXCEPT
|
||||
{
|
||||
void *yyp = yybuffer_.yyraw;
|
||||
void *yyp = yyraw_;
|
||||
return static_cast<T*> (yyp);
|
||||
}
|
||||
|
||||
@ -407,7 +418,7 @@ namespace isc { namespace dhcp {
|
||||
const T*
|
||||
yyas_ () const YY_NOEXCEPT
|
||||
{
|
||||
const void *yyp = yybuffer_.yyraw;
|
||||
const void *yyp = yyraw_;
|
||||
return static_cast<const T*> (yyp);
|
||||
}
|
||||
|
||||
@ -445,18 +456,19 @@ namespace isc { namespace dhcp {
|
||||
union
|
||||
{
|
||||
/// Strongest alignment constraints.
|
||||
long double yyalign_me;
|
||||
long double yyalign_me_;
|
||||
/// A buffer large enough to store any of the semantic values.
|
||||
char yyraw[size];
|
||||
} yybuffer_;
|
||||
char yyraw_[size];
|
||||
};
|
||||
|
||||
/// Whether the content is built: if defined, the name of the stored type.
|
||||
const std::type_info *yytypeid_;
|
||||
};
|
||||
|
||||
#else
|
||||
typedef PARSER4_STYPE semantic_type;
|
||||
#endif
|
||||
/// Backward compatibility (Bison 3.8).
|
||||
typedef value_type semantic_type;
|
||||
|
||||
/// Symbol locations.
|
||||
typedef location location_type;
|
||||
|
||||
@ -700,7 +712,7 @@ namespace isc { namespace dhcp {
|
||||
};
|
||||
|
||||
/// Token kind, as returned by yylex.
|
||||
typedef token::yytokentype token_kind_type;
|
||||
typedef token::token_kind_type token_kind_type;
|
||||
|
||||
/// Backward compatibility alias (Bison 3.6).
|
||||
typedef token_kind_type token_type;
|
||||
@ -1373,7 +1385,7 @@ namespace isc { namespace dhcp {
|
||||
typedef Base super_type;
|
||||
|
||||
/// Default constructor.
|
||||
basic_symbol ()
|
||||
basic_symbol () YY_NOEXCEPT
|
||||
: value ()
|
||||
, location ()
|
||||
{}
|
||||
@ -1514,6 +1526,8 @@ namespace isc { namespace dhcp {
|
||||
clear ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Destroy contents, and record that is empty.
|
||||
void clear () YY_NOEXCEPT
|
||||
{
|
||||
@ -1581,7 +1595,7 @@ switch (yykind)
|
||||
void move (basic_symbol& s);
|
||||
|
||||
/// The semantic value.
|
||||
semantic_type value;
|
||||
value_type value;
|
||||
|
||||
/// The location.
|
||||
location_type location;
|
||||
@ -1596,22 +1610,24 @@ switch (yykind)
|
||||
/// Type access provider for token (enum) based symbols.
|
||||
struct by_kind
|
||||
{
|
||||
/// Default constructor.
|
||||
by_kind ();
|
||||
|
||||
#if 201103L <= YY_CPLUSPLUS
|
||||
/// Move constructor.
|
||||
by_kind (by_kind&& that);
|
||||
#endif
|
||||
|
||||
/// Copy constructor.
|
||||
by_kind (const by_kind& that);
|
||||
|
||||
/// The symbol kind as needed by the constructor.
|
||||
typedef token_kind_type kind_type;
|
||||
|
||||
/// Default constructor.
|
||||
by_kind () YY_NOEXCEPT;
|
||||
|
||||
#if 201103L <= YY_CPLUSPLUS
|
||||
/// Move constructor.
|
||||
by_kind (by_kind&& that) YY_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
/// Copy constructor.
|
||||
by_kind (const by_kind& that) YY_NOEXCEPT;
|
||||
|
||||
/// Constructor from (external) token numbers.
|
||||
by_kind (kind_type t);
|
||||
by_kind (kind_type t) YY_NOEXCEPT;
|
||||
|
||||
|
||||
|
||||
/// Record that this symbol is empty.
|
||||
void clear () YY_NOEXCEPT;
|
||||
@ -1641,59 +1657,69 @@ switch (yykind)
|
||||
typedef basic_symbol<by_kind> super_type;
|
||||
|
||||
/// Empty symbol.
|
||||
symbol_type () {}
|
||||
symbol_type () YY_NOEXCEPT {}
|
||||
|
||||
/// Constructor for valueless symbols, and symbols from each type.
|
||||
#if 201103L <= YY_CPLUSPLUS
|
||||
symbol_type (int tok, location_type l)
|
||||
: super_type(token_type (tok), std::move (l))
|
||||
: super_type (token_kind_type (tok), std::move (l))
|
||||
#else
|
||||
symbol_type (int tok, const location_type& l)
|
||||
: super_type(token_type (tok), l)
|
||||
: super_type (token_kind_type (tok), l)
|
||||
#endif
|
||||
{
|
||||
#if !defined _MSC_VER || defined __clang__
|
||||
PARSER4__ASSERT (tok == token::TOKEN_END
|
||||
|| (token::TOKEN_PARSER4_error <= tok && tok <= token::TOKEN_SUB_CONFIG_CONTROL));
|
||||
#endif
|
||||
}
|
||||
#if 201103L <= YY_CPLUSPLUS
|
||||
symbol_type (int tok, bool v, location_type l)
|
||||
: super_type(token_type (tok), std::move (v), std::move (l))
|
||||
: super_type (token_kind_type (tok), std::move (v), std::move (l))
|
||||
#else
|
||||
symbol_type (int tok, const bool& v, const location_type& l)
|
||||
: super_type(token_type (tok), v, l)
|
||||
: super_type (token_kind_type (tok), v, l)
|
||||
#endif
|
||||
{
|
||||
#if !defined _MSC_VER || defined __clang__
|
||||
PARSER4__ASSERT (tok == token::TOKEN_BOOLEAN);
|
||||
#endif
|
||||
}
|
||||
#if 201103L <= YY_CPLUSPLUS
|
||||
symbol_type (int tok, double v, location_type l)
|
||||
: super_type(token_type (tok), std::move (v), std::move (l))
|
||||
: super_type (token_kind_type (tok), std::move (v), std::move (l))
|
||||
#else
|
||||
symbol_type (int tok, const double& v, const location_type& l)
|
||||
: super_type(token_type (tok), v, l)
|
||||
: super_type (token_kind_type (tok), v, l)
|
||||
#endif
|
||||
{
|
||||
#if !defined _MSC_VER || defined __clang__
|
||||
PARSER4__ASSERT (tok == token::TOKEN_FLOAT);
|
||||
#endif
|
||||
}
|
||||
#if 201103L <= YY_CPLUSPLUS
|
||||
symbol_type (int tok, int64_t v, location_type l)
|
||||
: super_type(token_type (tok), std::move (v), std::move (l))
|
||||
: super_type (token_kind_type (tok), std::move (v), std::move (l))
|
||||
#else
|
||||
symbol_type (int tok, const int64_t& v, const location_type& l)
|
||||
: super_type(token_type (tok), v, l)
|
||||
: super_type (token_kind_type (tok), v, l)
|
||||
#endif
|
||||
{
|
||||
#if !defined _MSC_VER || defined __clang__
|
||||
PARSER4__ASSERT (tok == token::TOKEN_INTEGER);
|
||||
#endif
|
||||
}
|
||||
#if 201103L <= YY_CPLUSPLUS
|
||||
symbol_type (int tok, std::string v, location_type l)
|
||||
: super_type(token_type (tok), std::move (v), std::move (l))
|
||||
: super_type (token_kind_type (tok), std::move (v), std::move (l))
|
||||
#else
|
||||
symbol_type (int tok, const std::string& v, const location_type& l)
|
||||
: super_type(token_type (tok), v, l)
|
||||
: super_type (token_kind_type (tok), v, l)
|
||||
#endif
|
||||
{
|
||||
#if !defined _MSC_VER || defined __clang__
|
||||
PARSER4__ASSERT (tok == token::TOKEN_STRING);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
@ -1742,7 +1768,7 @@ switch (yykind)
|
||||
/// YYSYMBOL. No bounds checking.
|
||||
static std::string symbol_name (symbol_kind_type yysymbol);
|
||||
|
||||
// Implementation of make_symbol for each symbol type.
|
||||
// Implementation of make_symbol for each token kind.
|
||||
#if 201103L <= YY_CPLUSPLUS
|
||||
static
|
||||
symbol_type
|
||||
@ -4939,19 +4965,19 @@ switch (yykind)
|
||||
|
||||
/// Whether the given \c yypact_ value indicates a defaulted state.
|
||||
/// \param yyvalue the value to check
|
||||
static bool yy_pact_value_is_default_ (int yyvalue);
|
||||
static bool yy_pact_value_is_default_ (int yyvalue) YY_NOEXCEPT;
|
||||
|
||||
/// Whether the given \c yytable_ value indicates a syntax error.
|
||||
/// \param yyvalue the value to check
|
||||
static bool yy_table_value_is_error_ (int yyvalue);
|
||||
static bool yy_table_value_is_error_ (int yyvalue) YY_NOEXCEPT;
|
||||
|
||||
static const short yypact_ninf_;
|
||||
static const signed char yytable_ninf_;
|
||||
|
||||
/// Convert a scanner token kind \a t to a symbol kind.
|
||||
/// In theory \a t should be a token_kind_type, but character literals
|
||||
/// are valid, yet not members of the token_type enum.
|
||||
static symbol_kind_type yytranslate_ (int t);
|
||||
/// are valid, yet not members of the token_kind_type enum.
|
||||
static symbol_kind_type yytranslate_ (int t) YY_NOEXCEPT;
|
||||
|
||||
/// Convert the symbol name \a n to a form suitable for a diagnostic.
|
||||
static std::string yytnamerr_ (const char *yystr);
|
||||
@ -4983,14 +5009,14 @@ switch (yykind)
|
||||
|
||||
static const short yycheck_[];
|
||||
|
||||
// YYSTOS[STATE-NUM] -- The (internal number of the) accessing
|
||||
// symbol of state STATE-NUM.
|
||||
// YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
|
||||
// state STATE-NUM.
|
||||
static const short yystos_[];
|
||||
|
||||
// YYR1[YYN] -- Symbol number of symbol that rule YYN derives.
|
||||
// YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM.
|
||||
static const short yyr1_[];
|
||||
|
||||
// YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.
|
||||
// YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM.
|
||||
static const signed char yyr2_[];
|
||||
|
||||
|
||||
@ -5089,7 +5115,7 @@ switch (yykind)
|
||||
typedef typename S::size_type size_type;
|
||||
typedef typename std::ptrdiff_t index_type;
|
||||
|
||||
stack (size_type n = 200)
|
||||
stack (size_type n = 200) YY_NOEXCEPT
|
||||
: seq_ (n)
|
||||
{}
|
||||
|
||||
@ -5168,7 +5194,7 @@ switch (yykind)
|
||||
class slice
|
||||
{
|
||||
public:
|
||||
slice (const stack& stack, index_type range)
|
||||
slice (const stack& stack, index_type range) YY_NOEXCEPT
|
||||
: stack_ (stack)
|
||||
, range_ (range)
|
||||
{}
|
||||
@ -5218,7 +5244,7 @@ switch (yykind)
|
||||
void yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym);
|
||||
|
||||
/// Pop \a n symbols from the stack.
|
||||
void yypop_ (int n = 1);
|
||||
void yypop_ (int n = 1) YY_NOEXCEPT;
|
||||
|
||||
/// Constants.
|
||||
enum
|
||||
@ -5236,7 +5262,7 @@ switch (yykind)
|
||||
|
||||
inline
|
||||
Dhcp4Parser::symbol_kind_type
|
||||
Dhcp4Parser::yytranslate_ (int t)
|
||||
Dhcp4Parser::yytranslate_ (int t) YY_NOEXCEPT
|
||||
{
|
||||
// YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to
|
||||
// TOKEN-NUM as returned by yylex.
|
||||
@ -5298,7 +5324,7 @@ switch (yykind)
|
||||
if (t <= 0)
|
||||
return symbol_kind::S_YYEOF;
|
||||
else if (t <= code_max)
|
||||
return YY_CAST (symbol_kind_type, translate_table[t]);
|
||||
return static_cast <symbol_kind_type> (translate_table[t]);
|
||||
else
|
||||
return symbol_kind::S_YYUNDEF;
|
||||
}
|
||||
@ -5348,6 +5374,7 @@ switch (yykind)
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename Base>
|
||||
Dhcp4Parser::symbol_kind_type
|
||||
Dhcp4Parser::basic_symbol<Base>::type_get () const YY_NOEXCEPT
|
||||
@ -5355,6 +5382,7 @@ switch (yykind)
|
||||
return this->kind ();
|
||||
}
|
||||
|
||||
|
||||
template <typename Base>
|
||||
bool
|
||||
Dhcp4Parser::basic_symbol<Base>::empty () const YY_NOEXCEPT
|
||||
@ -5406,13 +5434,13 @@ switch (yykind)
|
||||
|
||||
// by_kind.
|
||||
inline
|
||||
Dhcp4Parser::by_kind::by_kind ()
|
||||
Dhcp4Parser::by_kind::by_kind () YY_NOEXCEPT
|
||||
: kind_ (symbol_kind::S_YYEMPTY)
|
||||
{}
|
||||
|
||||
#if 201103L <= YY_CPLUSPLUS
|
||||
inline
|
||||
Dhcp4Parser::by_kind::by_kind (by_kind&& that)
|
||||
Dhcp4Parser::by_kind::by_kind (by_kind&& that) YY_NOEXCEPT
|
||||
: kind_ (that.kind_)
|
||||
{
|
||||
that.clear ();
|
||||
@ -5420,15 +5448,17 @@ switch (yykind)
|
||||
#endif
|
||||
|
||||
inline
|
||||
Dhcp4Parser::by_kind::by_kind (const by_kind& that)
|
||||
Dhcp4Parser::by_kind::by_kind (const by_kind& that) YY_NOEXCEPT
|
||||
: kind_ (that.kind_)
|
||||
{}
|
||||
|
||||
inline
|
||||
Dhcp4Parser::by_kind::by_kind (token_kind_type t)
|
||||
Dhcp4Parser::by_kind::by_kind (token_kind_type t) YY_NOEXCEPT
|
||||
: kind_ (yytranslate_ (t))
|
||||
{}
|
||||
|
||||
|
||||
|
||||
inline
|
||||
void
|
||||
Dhcp4Parser::by_kind::clear () YY_NOEXCEPT
|
||||
@ -5451,6 +5481,7 @@ switch (yykind)
|
||||
return kind_;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
Dhcp4Parser::symbol_kind_type
|
||||
Dhcp4Parser::by_kind::type_get () const YY_NOEXCEPT
|
||||
@ -5458,9 +5489,10 @@ switch (yykind)
|
||||
return this->kind ();
|
||||
}
|
||||
|
||||
|
||||
#line 14 "dhcp4_parser.yy"
|
||||
} } // isc::dhcp
|
||||
#line 5464 "dhcp4_parser.h"
|
||||
#line 5496 "dhcp4_parser.h"
|
||||
|
||||
|
||||
|
||||
|
@ -1532,8 +1532,8 @@ subnet4_param: valid_lifetime
|
||||
| ddns_use_conflict_resolution
|
||||
| hostname_char_set
|
||||
| hostname_char_replacement
|
||||
| allocator
|
||||
| store_extended_info
|
||||
| allocator
|
||||
| unknown_map_entry
|
||||
;
|
||||
|
||||
@ -1719,8 +1719,8 @@ shared_network_param: name
|
||||
| ddns_use_conflict_resolution
|
||||
| hostname_char_set
|
||||
| hostname_char_replacement
|
||||
| allocator
|
||||
| store_extended_info
|
||||
| allocator
|
||||
| unknown_map_entry
|
||||
;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// A Bison parser, made by GNU Bison 3.7.6.
|
||||
// A Bison parser, made by GNU Bison 3.8.2.
|
||||
|
||||
// Locations for Bison parsers in C++
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -942,6 +942,28 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu]
|
||||
}
|
||||
}
|
||||
|
||||
\"allocator\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_ALLOCATOR(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("allocator", driver.loc_);
|
||||
}
|
||||
}
|
||||
|
||||
\"pd-allocator\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_PD_ALLOCATOR(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("pd-allocator", driver.loc_);
|
||||
}
|
||||
}
|
||||
|
||||
\"statistic-default-sample-count\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -129,6 +129,8 @@ using namespace std;
|
||||
ENCAPSULATE "encapsulate"
|
||||
ARRAY "array"
|
||||
PARKED_PACKET_LIMIT "parked-packet-limit"
|
||||
ALLOCATOR "allocator"
|
||||
PD_ALLOCATOR "pd-allocator"
|
||||
|
||||
SHARED_NETWORKS "shared-networks"
|
||||
|
||||
@ -553,6 +555,8 @@ global_param: data_directory
|
||||
| reservations_lookup_first
|
||||
| compatibility
|
||||
| parked_packet_limit
|
||||
| allocator
|
||||
| pd_allocator
|
||||
| unknown_map_entry
|
||||
;
|
||||
|
||||
@ -775,6 +779,24 @@ parked_packet_limit: PARKED_PACKET_LIMIT COLON INTEGER {
|
||||
ctx.stack_.back()->set("parked-packet-limit", ppl);
|
||||
};
|
||||
|
||||
allocator: ALLOCATOR {
|
||||
ctx.unique("allocator", ctx.loc2pos(@1));
|
||||
ctx.enter(ctx.NO_KEYWORD);
|
||||
} COLON STRING {
|
||||
ElementPtr al(new StringElement($4, ctx.loc2pos(@4)));
|
||||
ctx.stack_.back()->set("allocator", al);
|
||||
ctx.leave();
|
||||
};
|
||||
|
||||
pd_allocator: PD_ALLOCATOR {
|
||||
ctx.unique("pd-allocator", ctx.loc2pos(@1));
|
||||
ctx.enter(ctx.NO_KEYWORD);
|
||||
} COLON STRING {
|
||||
ElementPtr al(new StringElement($4, ctx.loc2pos(@4)));
|
||||
ctx.stack_.back()->set("pd-allocator", al);
|
||||
ctx.leave();
|
||||
};
|
||||
|
||||
early_global_reservations_lookup: EARLY_GLOBAL_RESERVATIONS_LOOKUP COLON BOOLEAN {
|
||||
ctx.unique("early-global-reservations-lookup", ctx.loc2pos(@1));
|
||||
ElementPtr early(new BoolElement($3, ctx.loc2pos(@3)));
|
||||
@ -1537,6 +1559,8 @@ subnet6_param: preferred_lifetime
|
||||
| ddns_update_on_renew
|
||||
| ddns_use_conflict_resolution
|
||||
| store_extended_info
|
||||
| allocator
|
||||
| pd_allocator
|
||||
| unknown_map_entry
|
||||
;
|
||||
|
||||
@ -1711,6 +1735,8 @@ shared_network_param: name
|
||||
| ddns_update_on_renew
|
||||
| ddns_use_conflict_resolution
|
||||
| store_extended_info
|
||||
| allocator
|
||||
| pd_allocator
|
||||
| unknown_map_entry
|
||||
;
|
||||
|
||||
|
@ -818,7 +818,9 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
|
||||
(config_pair.first == "early-global-reservations-lookup") ||
|
||||
(config_pair.first == "ip-reservations-unique") ||
|
||||
(config_pair.first == "reservations-lookup-first") ||
|
||||
(config_pair.first == "parked-packet-limit")) {
|
||||
(config_pair.first == "parked-packet-limit") ||
|
||||
(config_pair.first == "allocator") ||
|
||||
(config_pair.first == "pd-allocator") ) {
|
||||
CfgMgr::instance().getStagingCfg()->addConfiguredGlobal(config_pair.first,
|
||||
config_pair.second);
|
||||
continue;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2014-2020 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2014-2022 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
|
||||
@ -14,6 +14,8 @@
|
||||
#include <dhcpsrv/d2_client_mgr.h>
|
||||
#include <asiolink/io_address.h>
|
||||
#include <stats/stats_mgr.h>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::asiolink;
|
||||
@ -60,6 +62,17 @@ namespace {
|
||||
/// - The reservations-in-subnet and reservations-out-of-pool flags are set to
|
||||
/// true to test that only out of pool reservations are honored.
|
||||
///
|
||||
/// - Configuration 5:
|
||||
/// - Selects random allocator for addresses.
|
||||
/// - One subnet with three distinct pools.
|
||||
/// - Random allocator enabled globally for addresses.
|
||||
/// - Iterative allocator for prefix delegation.
|
||||
///
|
||||
/// - Configuration 6:
|
||||
/// - Selects random allocator for delegated prefixes.
|
||||
/// - One subnet with three distinct pools.
|
||||
/// - Random allocator enabled globally for delegated prefixes.
|
||||
/// - Iterative allocator for address allocation.
|
||||
const char* CONFIGS[] = {
|
||||
// Configuration 0
|
||||
"{ \"interfaces-config\": {"
|
||||
@ -214,7 +227,65 @@ const char* CONFIGS[] = {
|
||||
" }"
|
||||
" ]"
|
||||
"} ]"
|
||||
"}"
|
||||
"}",
|
||||
|
||||
// Configuration 5
|
||||
"{ \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
"\"allocator\": \"random\","
|
||||
"\"pd-allocator\": \"iterative\","
|
||||
"\"preferred-lifetime\": 3000,"
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet6\": ["
|
||||
" {"
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"3000::20 - 3000::60\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"pd-pools\": ["
|
||||
" {"
|
||||
" \"prefix\": \"2001:db8:3::\", "
|
||||
" \"prefix-len\": 48, "
|
||||
" \"delegated-len\": 64"
|
||||
" }"
|
||||
" ],"
|
||||
" \"subnet\": \"3000::/32\", "
|
||||
" \"interface\": \"eth0\""
|
||||
" }"
|
||||
"],"
|
||||
"\"valid-lifetime\": 4000 }",
|
||||
|
||||
// Configuration 6
|
||||
"{ \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
"\"allocator\": \"iterative\","
|
||||
"\"pd-allocator\": \"random\","
|
||||
"\"preferred-lifetime\": 3000,"
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet6\": ["
|
||||
" {"
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"3000::20 - 3000::60\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"pd-pools\": ["
|
||||
" {"
|
||||
" \"prefix\": \"2001:db8:3::\", "
|
||||
" \"prefix-len\": 48, "
|
||||
" \"delegated-len\": 64"
|
||||
" }"
|
||||
" ],"
|
||||
" \"subnet\": \"3000::/32\", "
|
||||
" \"interface\": \"eth0\""
|
||||
" }"
|
||||
"],"
|
||||
"\"valid-lifetime\": 4000 }",
|
||||
};
|
||||
|
||||
/// @brief Test fixture class for testing 4-way exchange: Solicit-Advertise,
|
||||
@ -299,6 +370,14 @@ public:
|
||||
/// reservations-out-of-pool flag is set to true.
|
||||
void reservationIgnoredInOutOfPoolMode();
|
||||
|
||||
/// @brief This test verifies that random allocator is used according
|
||||
/// to the configuration and it allocates random addresses.
|
||||
void randomAddressAllocation();
|
||||
|
||||
/// @brief This test verifies that random allocator is used according
|
||||
/// to the configuration and it allocates random prefixes.
|
||||
void randomPrefixAllocation();
|
||||
|
||||
/// @brief Interface Manager's fake configuration control.
|
||||
IfaceMgrTestConfig iface_mgr_test_config_;
|
||||
};
|
||||
@ -873,4 +952,145 @@ TEST_F(SARRTest, reservationIgnoredInOutOfPoolModeMultiThreading) {
|
||||
reservationIgnoredInOutOfPoolMode();
|
||||
}
|
||||
|
||||
void
|
||||
SARRTest::randomAddressAllocation() {
|
||||
// Create the base client and server configuration.
|
||||
Dhcp6Client client;
|
||||
configure(CONFIGS[5], *client.getServer());
|
||||
|
||||
// Record what addresses have been allocated and in what order.
|
||||
std::set<std::string> allocated_na_set;
|
||||
std::vector<IOAddress> allocated_na_vector;
|
||||
std::set<std::string> allocated_pd_set;
|
||||
std::vector<IOAddress> allocated_pd_vector;
|
||||
// Simulate allocations from different clients.
|
||||
for (auto i = 0; i < 30; ++i) {
|
||||
// Create a client from the base client.
|
||||
Dhcp6Client next_client(client.getServer());
|
||||
next_client.requestAddress();
|
||||
next_client.requestPrefix();
|
||||
// Run 4-way exchange.
|
||||
ASSERT_NO_THROW(next_client.doSARR());
|
||||
// We should have one IA_NA and one IA_PD.
|
||||
auto leases_na = next_client.getLeasesByType(Lease::TYPE_NA);
|
||||
ASSERT_EQ(1, leases_na.size());
|
||||
auto leases_pd = next_client.getLeasesByType(Lease::TYPE_PD);
|
||||
ASSERT_EQ(1, leases_pd.size());
|
||||
// Remember allocated address and delegated prefix uniqueness
|
||||
// and order.
|
||||
allocated_na_set.insert(leases_na[0].toText());
|
||||
allocated_na_vector.push_back(leases_na[0].addr_);
|
||||
allocated_pd_set.insert(leases_pd[0].toText());
|
||||
allocated_pd_vector.push_back(leases_pd[0].addr_);
|
||||
}
|
||||
// Make sure that we have 30 distinct allocations for each lease type.
|
||||
ASSERT_EQ(30, allocated_na_set.size());
|
||||
ASSERT_EQ(30, allocated_na_vector.size());
|
||||
ASSERT_EQ(30, allocated_pd_set.size());
|
||||
ASSERT_EQ(30, allocated_pd_vector.size());
|
||||
|
||||
// Make sure that the addresses are not allocated iteratively.
|
||||
int consecutives = 0;
|
||||
for (auto i = 1; i < allocated_na_vector.size(); ++i) {
|
||||
// Record the cases when the previously allocated address is
|
||||
// lower by 1 (iterative allocation). Some cases like this are
|
||||
// possible even with the random allocation but they should be
|
||||
// very rare.
|
||||
if (IOAddress::increase(allocated_na_vector[i-1]) == allocated_na_vector[i]) {
|
||||
++consecutives;
|
||||
}
|
||||
}
|
||||
EXPECT_LT(consecutives, 10);
|
||||
|
||||
// Make sure that delegated prefixes have been allocated iteratively.
|
||||
consecutives = 0;
|
||||
for (auto i = 1; i < allocated_pd_vector.size(); ++i) {
|
||||
if (IOAddress::subtract(allocated_pd_vector[i], allocated_pd_vector[i-1]) == IOAddress("0:0:0:1::")) {
|
||||
++consecutives;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(29, consecutives);
|
||||
}
|
||||
|
||||
TEST_F(SARRTest, randomAddressAllocation) {
|
||||
Dhcpv6SrvMTTestGuard guard(*this, false);
|
||||
randomAddressAllocation();
|
||||
}
|
||||
|
||||
TEST_F(SARRTest, randomAddressAllocationMultiThreading) {
|
||||
Dhcpv6SrvMTTestGuard guard(*this, true);
|
||||
randomAddressAllocation();
|
||||
}
|
||||
|
||||
void
|
||||
SARRTest::randomPrefixAllocation() {
|
||||
// Create the base client and server configuration.
|
||||
Dhcp6Client client;
|
||||
configure(CONFIGS[6], *client.getServer());
|
||||
|
||||
// Record what addresses have been allocated and in what order.
|
||||
std::set<std::string> allocated_na_set;
|
||||
std::vector<IOAddress> allocated_na_vector;
|
||||
std::set<std::string> allocated_pd_set;
|
||||
std::vector<IOAddress> allocated_pd_vector;
|
||||
// Simulate allocations from different clients.
|
||||
for (auto i = 0; i < 30; ++i) {
|
||||
// Create a client from the base client.
|
||||
Dhcp6Client next_client(client.getServer());
|
||||
next_client.requestAddress();
|
||||
next_client.requestPrefix();
|
||||
// Run 4-way exchange.
|
||||
ASSERT_NO_THROW(next_client.doSARR());
|
||||
// We should have one IA_NA and one IA_PD.
|
||||
auto leases_na = next_client.getLeasesByType(Lease::TYPE_NA);
|
||||
ASSERT_EQ(1, leases_na.size());
|
||||
auto leases_pd = next_client.getLeasesByType(Lease::TYPE_PD);
|
||||
ASSERT_EQ(1, leases_pd.size());
|
||||
// Remember allocated address and delegated prefix uniqueness
|
||||
// and order.
|
||||
allocated_na_set.insert(leases_na[0].toText());
|
||||
allocated_na_vector.push_back(leases_na[0].addr_);
|
||||
allocated_pd_set.insert(leases_pd[0].toText());
|
||||
allocated_pd_vector.push_back(leases_pd[0].addr_);
|
||||
}
|
||||
// Make sure that we have 30 distinct allocations for each lease type.
|
||||
ASSERT_EQ(30, allocated_na_set.size());
|
||||
ASSERT_EQ(30, allocated_na_vector.size());
|
||||
ASSERT_EQ(30, allocated_pd_set.size());
|
||||
ASSERT_EQ(30, allocated_pd_vector.size());
|
||||
|
||||
// Make sure that the addresses have been allocated iteratively.
|
||||
int consecutives = 0;
|
||||
for (auto i = 1; i < allocated_na_vector.size(); ++i) {
|
||||
// Record the cases when the previously allocated address is
|
||||
// lower by 1 (iterative allocation).
|
||||
if (IOAddress::increase(allocated_na_vector[i-1]) == allocated_na_vector[i]) {
|
||||
++consecutives;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that addresses have been allocated iteratively.
|
||||
EXPECT_EQ(29, consecutives);
|
||||
|
||||
// Make sure that delegated prefixes have been allocated randomly.
|
||||
consecutives = 0;
|
||||
for (auto i = 1; i < allocated_pd_vector.size(); ++i) {
|
||||
if (IOAddress::subtract(allocated_pd_vector[i], allocated_pd_vector[i-1]) == IOAddress("0:0:0:1::")) {
|
||||
++consecutives;
|
||||
}
|
||||
}
|
||||
EXPECT_LT(consecutives, 10);
|
||||
}
|
||||
|
||||
TEST_F(SARRTest, randomPrefixAllocation) {
|
||||
Dhcpv6SrvMTTestGuard guard(*this, false);
|
||||
randomPrefixAllocation();
|
||||
}
|
||||
|
||||
TEST_F(SARRTest, randomPrefixAllocationMultiThreading) {
|
||||
Dhcpv6SrvMTTestGuard guard(*this, true);
|
||||
randomPrefixAllocation();
|
||||
}
|
||||
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
@ -16,34 +16,18 @@ namespace dhcp {
|
||||
|
||||
SubnetAllocationState::SubnetAllocationState()
|
||||
: AllocationState(), mutex_(new std::mutex) {
|
||||
// Initialize timestamps for each lease type to negative infinity.
|
||||
last_allocated_time_[Lease::TYPE_V4] = boost::posix_time::neg_infin;
|
||||
last_allocated_time_[Lease::TYPE_NA] = boost::posix_time::neg_infin;
|
||||
last_allocated_time_[Lease::TYPE_TA] = boost::posix_time::neg_infin;
|
||||
last_allocated_time_[Lease::TYPE_PD] = boost::posix_time::neg_infin;
|
||||
last_allocated_time_ = boost::posix_time::neg_infin;
|
||||
}
|
||||
|
||||
boost::posix_time::ptime
|
||||
SubnetAllocationState::getLastAllocatedTime(Lease::Type type) const {
|
||||
SubnetAllocationState::getLastAllocatedTime() const {
|
||||
MultiThreadingLock lock(*mutex_);
|
||||
return (getLastAllocatedTimeInternal(type));
|
||||
}
|
||||
|
||||
boost::posix_time::ptime
|
||||
SubnetAllocationState::getLastAllocatedTimeInternal(Lease::Type type) const {
|
||||
auto t = last_allocated_time_.find(type);
|
||||
if (t != last_allocated_time_.end()) {
|
||||
return (t->second);
|
||||
}
|
||||
|
||||
// This shouldn't happen, because we have initialized the structure
|
||||
// for all lease types.
|
||||
return (boost::posix_time::neg_infin);
|
||||
return (last_allocated_time_);
|
||||
}
|
||||
|
||||
void
|
||||
SubnetAllocationState::setCurrentAllocatedTimeInternal(Lease::Type type) {
|
||||
last_allocated_time_[type] = boost::posix_time::microsec_clock::universal_time();
|
||||
SubnetAllocationState::setCurrentAllocatedTimeInternal() {
|
||||
last_allocated_time_ = boost::posix_time::microsec_clock::universal_time();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -55,46 +55,26 @@ public:
|
||||
|
||||
/// @brief Returns last allocation time for the specified lease type.
|
||||
///
|
||||
/// @param type specifies a lease type for which the last allocation
|
||||
/// time should be returned.
|
||||
/// @return Last allocation time for the lease type or
|
||||
/// @c boost::posix_time::neg_infin when no leases have been allocated
|
||||
/// from this subnet yet.
|
||||
boost::posix_time::ptime
|
||||
getLastAllocatedTime(Lease::Type type) const;
|
||||
getLastAllocatedTime() const;
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief Sets the last allocation time to current for a lease type.
|
||||
/// @brief Sets the last allocation time to current.
|
||||
///
|
||||
/// This function should be called by derived classes. It should be
|
||||
/// called in the thread-safe context.
|
||||
///
|
||||
/// @param type specifies a lease type for which the last allocation
|
||||
/// time should be set to the current time.
|
||||
void setCurrentAllocatedTimeInternal(Lease::Type type);
|
||||
|
||||
/// @brief Returns the last allocation time of a specified lease type.
|
||||
///
|
||||
/// It should be called in a thread safe context.
|
||||
///
|
||||
/// @param lease_type Lease type for which last allocation timestamp should
|
||||
/// be returned.
|
||||
///
|
||||
/// @return time when a lease of a specified type has been allocated from
|
||||
/// this subnet. The negative infinity time is returned if a lease type is
|
||||
/// not recognized (which is unlikely).
|
||||
boost::posix_time::ptime
|
||||
getLastAllocatedTimeInternal(Lease::Type type) const;
|
||||
void setCurrentAllocatedTimeInternal();
|
||||
|
||||
/// @brief Mutex used for thread-safe access to the state members.
|
||||
boost::scoped_ptr<std::mutex> mutex_;
|
||||
|
||||
/// @brief Timestamp indicating when a lease of a specified type has been
|
||||
/// last allocated from the subnet.
|
||||
///
|
||||
/// @note: This map is protected by the mutex.
|
||||
std::map<Lease::Type, boost::posix_time::ptime> last_allocated_time_;
|
||||
/// @brief Timestamp indicating when a lease has been last allocated
|
||||
/// from the subnet.
|
||||
boost::posix_time::ptime last_allocated_time_;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<SubnetAllocationState> SubnetAllocationStatePtr;
|
||||
|
@ -50,6 +50,7 @@ CfgGlobals::nameToIndex = {
|
||||
{ "ddns-update-on-renew", DDNS_UPDATE_ON_RENEW },
|
||||
{ "ddns-use-conflict-resolution", DDNS_USE_CONFLICT_RESOLUTION },
|
||||
{ "parked-packet-limit", PARKED_PACKET_LIMIT },
|
||||
{ "allocator", ALLOCATOR },
|
||||
|
||||
// DHCPv4 specific parameters.
|
||||
{ "echo-client-id", ECHO_CLIENT_ID },
|
||||
@ -58,13 +59,13 @@ CfgGlobals::nameToIndex = {
|
||||
{ "next-server", NEXT_SERVER },
|
||||
{ "server-hostname", SERVER_HOSTNAME },
|
||||
{ "boot-file-name", BOOT_FILE_NAME },
|
||||
{ "allocator", ALLOCATOR },
|
||||
|
||||
// DHCPv6 specific parameters.
|
||||
{ "data-directory", DATA_DIRECTORY },
|
||||
{ "preferred-lifetime", PREFERRED_LIFETIME },
|
||||
{ "min-preferred-lifetime", MIN_PREFERRED_LIFETIME },
|
||||
{ "max-preferred-lifetime", MAX_PREFERRED_LIFETIME }
|
||||
{ "max-preferred-lifetime", MAX_PREFERRED_LIFETIME },
|
||||
{ "pd-allocator", PD_ALLOCATOR }
|
||||
};
|
||||
|
||||
// Load time sanity check.
|
||||
|
@ -73,6 +73,7 @@ public:
|
||||
DDNS_UPDATE_ON_RENEW,
|
||||
DDNS_USE_CONFLICT_RESOLUTION,
|
||||
PARKED_PACKET_LIMIT,
|
||||
ALLOCATOR,
|
||||
|
||||
// DHCPv4 specific parameters.
|
||||
ECHO_CLIENT_ID,
|
||||
@ -81,13 +82,13 @@ public:
|
||||
NEXT_SERVER,
|
||||
SERVER_HOSTNAME,
|
||||
BOOT_FILE_NAME,
|
||||
ALLOCATOR,
|
||||
|
||||
// DHCPv6 specific parameters.
|
||||
DATA_DIRECTORY,
|
||||
PREFERRED_LIFETIME,
|
||||
MIN_PREFERRED_LIFETIME,
|
||||
MAX_PREFERRED_LIFETIME,
|
||||
PD_ALLOCATOR,
|
||||
|
||||
// Size sentinel.
|
||||
SIZE
|
||||
|
@ -26,47 +26,21 @@ SubnetIterativeAllocationState::create(const SubnetPtr& subnet) {
|
||||
SubnetIterativeAllocationState::SubnetIterativeAllocationState(const IOAddress& prefix,
|
||||
const uint8_t prefix_length)
|
||||
: SubnetAllocationState(),
|
||||
last_allocated_address_(lastAddrInPrefix(prefix, prefix_length)),
|
||||
last_allocated_ta_(lastAddrInPrefix(prefix, prefix_length)),
|
||||
last_allocated_pd_(lastAddrInPrefix(prefix, prefix_length)) {
|
||||
last_allocated_(lastAddrInPrefix(prefix, prefix_length)) {
|
||||
}
|
||||
|
||||
IOAddress
|
||||
SubnetIterativeAllocationState::getLastAllocated(Lease::Type type) const {
|
||||
SubnetIterativeAllocationState::getLastAllocated() const {
|
||||
MultiThreadingLock lock(*mutex_);
|
||||
switch (type) {
|
||||
case Lease::TYPE_V4:
|
||||
case Lease::TYPE_NA:
|
||||
return (last_allocated_address_);
|
||||
case Lease::TYPE_TA:
|
||||
return (last_allocated_ta_);
|
||||
case Lease::TYPE_PD:
|
||||
return (last_allocated_pd_);
|
||||
default:
|
||||
isc_throw(BadValue, "pool type " << type << " not supported");
|
||||
}
|
||||
return (last_allocated_);
|
||||
}
|
||||
|
||||
void
|
||||
SubnetIterativeAllocationState::setLastAllocated(Lease::Type type, const IOAddress& address) {
|
||||
SubnetIterativeAllocationState::setLastAllocated(const IOAddress& address) {
|
||||
MultiThreadingLock lock(*mutex_);
|
||||
switch (type) {
|
||||
case Lease::TYPE_V4:
|
||||
case Lease::TYPE_NA:
|
||||
last_allocated_address_ = address;
|
||||
break;
|
||||
case Lease::TYPE_TA:
|
||||
last_allocated_ta_ = address;
|
||||
break;
|
||||
case Lease::TYPE_PD:
|
||||
last_allocated_pd_ = address;
|
||||
break;
|
||||
default:
|
||||
isc_throw(BadValue, "pool type " << type << " not supported");
|
||||
}
|
||||
|
||||
// Update the timestamp of last allocation.
|
||||
setCurrentAllocatedTimeInternal(type);
|
||||
last_allocated_ = address;
|
||||
// Update the timestamp of the last allocation.
|
||||
setCurrentAllocatedTimeInternal();
|
||||
}
|
||||
|
||||
PoolIterativeAllocationStatePtr
|
||||
|
@ -49,37 +49,26 @@ public:
|
||||
|
||||
/// @brief Returns last allocated address or prefix.
|
||||
///
|
||||
/// @param type type of the last allocated lease to be returned.
|
||||
/// @return last allocated address or prefix of a given type.
|
||||
asiolink::IOAddress getLastAllocated(Lease::Type type) const;
|
||||
/// @return last allocated address or prefix.
|
||||
asiolink::IOAddress getLastAllocated() const;
|
||||
|
||||
/// @brief Sets last allocated address or prefix.
|
||||
///
|
||||
/// @param type type of the last allocated lease set.
|
||||
/// @param address an address or prefix last allocated.
|
||||
void setLastAllocated(Lease::Type type, const asiolink::IOAddress& address);
|
||||
void setLastAllocated(const asiolink::IOAddress& address);
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Last allocated address.
|
||||
/// @brief Last allocated address or delegated prefix.
|
||||
///
|
||||
/// This is the last allocated address that was previously allocated from
|
||||
/// the particular subnet. It should be noted that although the value
|
||||
/// is usually correct, there are cases when it is invalid, e.g. after
|
||||
/// removing a pool, restarting or changing allocation algorithms. For
|
||||
/// that purpose it should be only considered a help that should not be
|
||||
/// fully trusted.
|
||||
asiolink::IOAddress last_allocated_address_;
|
||||
|
||||
/// @brief Last allocated temporary address.
|
||||
///
|
||||
/// See @ref last_allocated_address_ for details.
|
||||
asiolink::IOAddress last_allocated_ta_;
|
||||
|
||||
/// @brief Last allocated IPv6 prefix.
|
||||
///
|
||||
/// See @ref last_allocated_address_ for details.
|
||||
asiolink::IOAddress last_allocated_pd_;
|
||||
/// This is the last allocated address or delegated prefix that was
|
||||
/// previously allocated from the particular subnet. It should be
|
||||
/// noted that although the value is usually correct, there are
|
||||
/// cases when it is invalid, e.g. after removing a pool,
|
||||
/// restarting or changing allocation algorithms. For that purpose
|
||||
/// it should be only considered a help that should not be fully
|
||||
/// trusted.
|
||||
asiolink::IOAddress last_allocated_;
|
||||
};
|
||||
|
||||
/// @brief Forward declaration of the @c PoolIterativeAllocationState.
|
||||
|
@ -97,7 +97,7 @@ IterativeAllocator::pickAddressInternal(const ClientClasses& client_classes,
|
||||
// Let's get the last allocated address. It is usually set correctly,
|
||||
// but there are times when it won't be (like after removing a pool or
|
||||
// perhaps restarting the server).
|
||||
IOAddress last = getSubnetState()->getLastAllocated(pool_type_);
|
||||
IOAddress last = getSubnetState()->getLastAllocated();
|
||||
bool valid = true;
|
||||
bool retrying = false;
|
||||
|
||||
@ -156,7 +156,7 @@ IterativeAllocator::pickAddressInternal(const ClientClasses& client_classes,
|
||||
if (!valid && (last == (*it)->getFirstAddress())) {
|
||||
// Pool was (re)initialized
|
||||
getPoolState(*it)->setLastAllocated(last);
|
||||
getSubnetState()->setLastAllocated(pool_type_, last);
|
||||
getSubnetState()->setLastAllocated(last);
|
||||
return (last);
|
||||
}
|
||||
// still can be bogus
|
||||
@ -186,7 +186,7 @@ IterativeAllocator::pickAddressInternal(const ClientClasses& client_classes,
|
||||
// the next one is in the pool as well, so we haven't hit
|
||||
// pool boundary yet
|
||||
getPoolState(*it)->setLastAllocated(next);
|
||||
getSubnetState()->setLastAllocated(pool_type_, next);
|
||||
getSubnetState()->setLastAllocated(next);
|
||||
return (next);
|
||||
}
|
||||
|
||||
@ -209,17 +209,17 @@ IterativeAllocator::pickAddressInternal(const ClientClasses& client_classes,
|
||||
// ok to access first element directly. We checked that pools is non-empty
|
||||
last = getPoolState(*first)->getLastAllocated();
|
||||
getPoolState(*first)->setLastAllocated(last);
|
||||
getSubnetState()->setLastAllocated(pool_type_, last);
|
||||
getSubnetState()->setLastAllocated(last);
|
||||
return (last);
|
||||
}
|
||||
|
||||
SubnetIterativeAllocationStatePtr
|
||||
IterativeAllocator::getSubnetState() const {
|
||||
auto subnet = subnet_.lock();
|
||||
if (!subnet->getAllocationState()) {
|
||||
subnet->setAllocationState(SubnetIterativeAllocationState::create(subnet));
|
||||
if (!subnet->getAllocationState(pool_type_)) {
|
||||
subnet->setAllocationState(pool_type_, SubnetIterativeAllocationState::create(subnet));
|
||||
}
|
||||
return (boost::dynamic_pointer_cast<SubnetIterativeAllocationState>(subnet->getAllocationState()));
|
||||
return (boost::dynamic_pointer_cast<SubnetIterativeAllocationState>(subnet->getAllocationState(pool_type_)));
|
||||
}
|
||||
|
||||
PoolIterativeAllocationStatePtr
|
||||
|
@ -368,6 +368,11 @@ Network6::toElement() const {
|
||||
map->set("rapid-commit", Element::create(rapid_commit_.get()));
|
||||
}
|
||||
|
||||
// Set pd-allocator
|
||||
if (!pd_allocator_type_.unspecified()) {
|
||||
map->set("pd-allocator", Element::create(pd_allocator_type_));
|
||||
}
|
||||
|
||||
return (map);
|
||||
}
|
||||
|
||||
|
@ -1400,6 +1400,28 @@ public:
|
||||
rapid_commit_ = rapid_commit;
|
||||
};
|
||||
|
||||
/// @brief Returns allocator type for prefix delegation.
|
||||
///
|
||||
/// @param inheritance inheritance mode to be used.
|
||||
util::Optional<std::string>
|
||||
getPdAllocatorType(const Inheritance& inheritance = Inheritance::ALL) const {
|
||||
return (getProperty<Network6>(&Network6::getPdAllocatorType,
|
||||
pd_allocator_type_,
|
||||
inheritance,
|
||||
CfgGlobals::PD_ALLOCATOR));
|
||||
}
|
||||
|
||||
/// @brief Sets new allocator type for prefix delegation.
|
||||
///
|
||||
/// It doesn't set the actual allocator instance. It merely remembers the
|
||||
/// value specified in the configuration, so it can be output in the
|
||||
/// @c toElement call.
|
||||
///
|
||||
/// @param allocator_type new allocator type to use.
|
||||
void setPdAllocatorType(const util::Optional<std::string>& allocator_type) {
|
||||
pd_allocator_type_ = allocator_type;
|
||||
}
|
||||
|
||||
/// @brief Unparses network object.
|
||||
///
|
||||
/// @return A pointer to unparsed network configuration.
|
||||
@ -1419,6 +1441,9 @@ private:
|
||||
/// It's default value is false, which indicates that the Rapid
|
||||
/// Commit is disabled for the subnet.
|
||||
util::Optional<bool> rapid_commit_;
|
||||
|
||||
/// @brief Allocator used for prefix delegation.
|
||||
util::Optional<std::string> pd_allocator_type_;
|
||||
};
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
|
@ -633,39 +633,22 @@ SubnetConfigParser::createSubnet(ConstElementPtr params) {
|
||||
// Call the subclass's method to instantiate the subnet
|
||||
initSubnet(params, addr, len);
|
||||
|
||||
std::string allocator_type = (params->contains("allocator") ?
|
||||
getString(params, "allocator") : "iterative");
|
||||
subnet_->setAllocatorType(allocator_type);
|
||||
if (allocator_type == "random") {
|
||||
subnet_->setAllocator(Lease::TYPE_V4,
|
||||
boost::make_shared<RandomAllocator>
|
||||
(Lease::TYPE_V4, subnet_));
|
||||
subnet_->setAllocationState(SubnetAllocationStatePtr());
|
||||
|
||||
} else if (allocator_type == "iterative") {
|
||||
subnet_->setAllocator(Lease::TYPE_V4,
|
||||
boost::make_shared<IterativeAllocator>
|
||||
(Lease::TYPE_V4, subnet_));
|
||||
subnet_->setAllocationState(SubnetIterativeAllocationState::create(subnet_));
|
||||
|
||||
} else {
|
||||
ConstElementPtr error = params->get("allocator");
|
||||
isc_throw(DhcpConfigError, "supported allocators are: iterative and random ("
|
||||
<< error->getPosition() << ")");
|
||||
std::string allocator_type = "iterative";
|
||||
if (params->contains("allocator")) {
|
||||
allocator_type = getString(params, "allocator");
|
||||
if ((allocator_type != "iterative") && (allocator_type != "random")) {
|
||||
ConstElementPtr error = params->get("allocator");
|
||||
isc_throw(DhcpConfigError, "supported allocators are: iterative and random ("
|
||||
<< error->getPosition() << ")");
|
||||
}
|
||||
}
|
||||
|
||||
subnet_->setAllocatorType(allocator_type);
|
||||
|
||||
// Add pools to it.
|
||||
for (PoolStorage::iterator it = pools_->begin(); it != pools_->end();
|
||||
++it) {
|
||||
try {
|
||||
auto pool = *it;
|
||||
if (allocator_type == "random") {
|
||||
pool->setAllocationState(PoolRandomAllocationState::create(pool));
|
||||
} else {
|
||||
pool->setAllocationState(PoolIterativeAllocationState::create(pool));
|
||||
}
|
||||
subnet_->addPool(pool);
|
||||
subnet_->addPool(*it);
|
||||
} catch (const BadValue& ex) {
|
||||
// addPool() can throw BadValue if the pool is overlapping or
|
||||
// is out of bounds for the subnet.
|
||||
@ -749,6 +732,28 @@ Subnet4ConfigParser::parse(ConstElementPtr subnet) {
|
||||
}
|
||||
}
|
||||
|
||||
if (subnet_->getAllocatorType() == "random") {
|
||||
subnet_->setAllocator(Lease::TYPE_V4,
|
||||
boost::make_shared<RandomAllocator>
|
||||
(Lease::TYPE_V4, subnet_));
|
||||
subnet_->setAllocationState(Lease::TYPE_V4, SubnetAllocationStatePtr());
|
||||
|
||||
for (auto pool : *pools_) {
|
||||
pool->setAllocationState(PoolRandomAllocationState::create(pool));
|
||||
}
|
||||
|
||||
} else if (subnet_->getAllocatorType() == "iterative") {
|
||||
subnet_->setAllocator(Lease::TYPE_V4,
|
||||
boost::make_shared<IterativeAllocator>
|
||||
(Lease::TYPE_V4, subnet_));
|
||||
subnet_->setAllocationState(Lease::TYPE_V4, SubnetIterativeAllocationState::create(subnet_));
|
||||
|
||||
for (auto pool : *pools_) {
|
||||
pool->setAllocationState(PoolIterativeAllocationState::create(pool));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (sn4ptr);
|
||||
}
|
||||
|
||||
@ -1256,6 +1261,72 @@ Subnet6ConfigParser::parse(ConstElementPtr subnet) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string allocator_type = "iterative";
|
||||
if (subnet->contains("pd-allocator")) {
|
||||
allocator_type = getString(subnet, "pd-allocator");
|
||||
if ((allocator_type != "iterative") && (allocator_type != "random")) {
|
||||
ConstElementPtr error = subnet->get("pd-allocator");
|
||||
isc_throw(DhcpConfigError, "supported allocators are: iterative and random ("
|
||||
<< error->getPosition() << ")");
|
||||
}
|
||||
}
|
||||
sn6ptr->setPdAllocatorType(allocator_type);
|
||||
|
||||
if (sn6ptr->getAllocatorType() == "random") {
|
||||
sn6ptr->setAllocator(Lease::TYPE_NA,
|
||||
boost::make_shared<RandomAllocator>
|
||||
(Lease::TYPE_NA, sn6ptr));
|
||||
sn6ptr->setAllocator(Lease::TYPE_TA,
|
||||
boost::make_shared<RandomAllocator>
|
||||
(Lease::TYPE_TA, sn6ptr));
|
||||
sn6ptr->setAllocationState(Lease::TYPE_NA, SubnetAllocationStatePtr());
|
||||
sn6ptr->setAllocationState(Lease::TYPE_TA, SubnetAllocationStatePtr());
|
||||
|
||||
} else {
|
||||
sn6ptr->setAllocator(Lease::TYPE_NA,
|
||||
boost::make_shared<IterativeAllocator>
|
||||
(Lease::TYPE_NA, sn6ptr));
|
||||
sn6ptr->setAllocator(Lease::TYPE_TA,
|
||||
boost::make_shared<IterativeAllocator>
|
||||
(Lease::TYPE_TA, sn6ptr));
|
||||
sn6ptr->setAllocationState(Lease::TYPE_NA, SubnetIterativeAllocationState::create(sn6ptr));
|
||||
sn6ptr->setAllocationState(Lease::TYPE_TA, SubnetIterativeAllocationState::create(sn6ptr));
|
||||
}
|
||||
|
||||
if (sn6ptr->getPdAllocatorType() == "random") {
|
||||
sn6ptr->setAllocator(Lease::TYPE_PD,
|
||||
boost::make_shared<RandomAllocator>
|
||||
(Lease::TYPE_PD, sn6ptr));
|
||||
sn6ptr->setAllocationState(Lease::TYPE_PD, SubnetAllocationStatePtr());
|
||||
|
||||
} else {
|
||||
sn6ptr->setAllocator(Lease::TYPE_PD,
|
||||
boost::make_shared<IterativeAllocator>
|
||||
(Lease::TYPE_PD, sn6ptr));
|
||||
sn6ptr->setAllocationState(Lease::TYPE_PD, SubnetIterativeAllocationState::create(sn6ptr));
|
||||
}
|
||||
|
||||
for (auto pool : *pools_) {
|
||||
switch (pool->getType()) {
|
||||
case Lease::TYPE_V4:
|
||||
case Lease::TYPE_NA:
|
||||
case Lease::TYPE_TA:
|
||||
if (sn6ptr->getAllocatorType() == "random") {
|
||||
pool->setAllocationState(PoolRandomAllocationState::create(pool));
|
||||
} else {
|
||||
pool->setAllocationState(PoolIterativeAllocationState::create(pool));
|
||||
}
|
||||
break;
|
||||
case Lease::TYPE_PD:
|
||||
if (sn6ptr->getPdAllocatorType() == "random") {
|
||||
pool->setAllocationState(PoolRandomAllocationState::create(pool));
|
||||
} else {
|
||||
pool->setAllocationState(PoolIterativeAllocationState::create(pool));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (sn6ptr);
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ const SimpleDefaults SimpleParser4::GLOBAL4_DEFAULTS = {
|
||||
{ "ddns-update-on-renew", Element::boolean, "false" },
|
||||
{ "ddns-use-conflict-resolution", Element::boolean, "true" },
|
||||
{ "parked-packet-limit", Element::integer, "256" },
|
||||
{ "allocator", Element::string, "iterative" },
|
||||
{ "allocator", Element::string, "iterative" },
|
||||
};
|
||||
|
||||
/// @brief This table defines all option definition parameters.
|
||||
|
@ -100,6 +100,8 @@ const SimpleKeywords SimpleParser6::GLOBAL6_PARAMETERS = {
|
||||
{ "ddns-use-conflict-resolution", Element::boolean },
|
||||
{ "compatibility", Element::map },
|
||||
{ "parked-packet-limit", Element::integer },
|
||||
{ "allocator", Element::string },
|
||||
{ "pd-allocator", Element::string }
|
||||
};
|
||||
|
||||
/// @brief This table defines default global values for DHCPv6
|
||||
@ -135,7 +137,9 @@ const SimpleDefaults SimpleParser6::GLOBAL6_DEFAULTS = {
|
||||
{ "reservations-lookup-first", Element::boolean, "false" },
|
||||
{ "ddns-update-on-renew", Element::boolean, "false" },
|
||||
{ "ddns-use-conflict-resolution", Element::boolean, "true" },
|
||||
{ "parked-packet-limit", Element::integer, "256" }
|
||||
{ "parked-packet-limit", Element::integer, "256" },
|
||||
{ "allocator", Element::string, "iterative" },
|
||||
{ "pd-allocator", Element::string, "iterative" }
|
||||
};
|
||||
|
||||
/// @brief This table defines all option definition parameters.
|
||||
@ -243,7 +247,9 @@ const SimpleKeywords SimpleParser6::SUBNET6_PARAMETERS = {
|
||||
{ "cache-threshold", Element::real },
|
||||
{ "cache-max-age", Element::integer },
|
||||
{ "ddns-update-on-renew", Element::boolean },
|
||||
{ "ddns-use-conflict-resolution", Element::boolean }
|
||||
{ "ddns-use-conflict-resolution", Element::boolean },
|
||||
{ "allocator", Element::string },
|
||||
{ "pd-allocator", Element::string }
|
||||
};
|
||||
|
||||
/// @brief This table defines default values for each IPv6 subnet.
|
||||
@ -296,7 +302,9 @@ const ParamsList SimpleParser6::INHERIT_TO_SUBNET6 = {
|
||||
"t2-percent",
|
||||
"store-extended-info",
|
||||
"cache-threshold",
|
||||
"cache-max-age"
|
||||
"cache-max-age",
|
||||
"allocator",
|
||||
"pd-allocator"
|
||||
};
|
||||
|
||||
/// @brief This table defines all pool parameters.
|
||||
@ -378,7 +386,9 @@ const SimpleKeywords SimpleParser6::SHARED_NETWORK6_PARAMETERS = {
|
||||
{ "cache-threshold", Element::real },
|
||||
{ "cache-max-age", Element::integer },
|
||||
{ "ddns-update-on-renew", Element::boolean },
|
||||
{ "ddns-use-conflict-resolution", Element::boolean }
|
||||
{ "ddns-use-conflict-resolution", Element::boolean },
|
||||
{ "allocator", Element::string },
|
||||
{ "pd-allocator", Element::string }
|
||||
};
|
||||
|
||||
/// @brief This table defines default values for each IPv6 subnet.
|
||||
|
@ -307,16 +307,16 @@ public:
|
||||
if ((*s)->getClientClass().get() != selected_subnet->getClientClass().get()) {
|
||||
continue;
|
||||
}
|
||||
auto current_subnet_state = (*s)->getAllocationState();
|
||||
auto current_subnet_state = (*s)->getAllocationState(lease_type);
|
||||
if (!current_subnet_state) {
|
||||
continue;
|
||||
}
|
||||
auto selected_subnet_state = selected_subnet->getAllocationState();
|
||||
auto selected_subnet_state = selected_subnet->getAllocationState(lease_type);
|
||||
if (!selected_subnet_state) {
|
||||
continue;
|
||||
}
|
||||
if (current_subnet_state->getLastAllocatedTime(lease_type) >
|
||||
selected_subnet_state->getLastAllocatedTime(lease_type)) {
|
||||
if (current_subnet_state->getLastAllocatedTime() >
|
||||
selected_subnet_state->getLastAllocatedTime()) {
|
||||
preferred_subnet = (*s);
|
||||
}
|
||||
}
|
||||
|
@ -210,6 +210,8 @@ Subnet4::create(const IOAddress& prefix, uint8_t length,
|
||||
subnet->setAllocator(Lease::TYPE_V4,
|
||||
boost::make_shared<IterativeAllocator>
|
||||
(Lease::TYPE_V4, subnet));
|
||||
subnet->setAllocationState(Lease::TYPE_V4,
|
||||
SubnetIterativeAllocationState::create(subnet));
|
||||
|
||||
return (subnet);
|
||||
}
|
||||
@ -316,6 +318,22 @@ Subnet::setAllocator(Lease::Type type, const AllocatorPtr& allocator) {
|
||||
allocators_[type] = allocator;
|
||||
}
|
||||
|
||||
SubnetAllocationStatePtr
|
||||
Subnet::getAllocationState(Lease::Type type) const {
|
||||
auto state = allocation_states_.find(type);
|
||||
|
||||
if (state == allocation_states_.end()) {
|
||||
isc_throw(BadValue, "no allocation state initialized for pool type "
|
||||
<< Lease::typeToText(type));
|
||||
}
|
||||
return (state->second);
|
||||
}
|
||||
|
||||
void
|
||||
Subnet::setAllocationState(Lease::Type type, const SubnetAllocationStatePtr& allocation_state) {
|
||||
allocation_states_[type] = allocation_state;
|
||||
}
|
||||
|
||||
const PoolPtr Subnet::getPool(Lease::Type type, const isc::asiolink::IOAddress& hint,
|
||||
bool anypool /* true */) const {
|
||||
// check if the type is valid (and throw if it isn't)
|
||||
@ -582,16 +600,24 @@ Subnet6::create(const IOAddress& prefix, uint8_t length,
|
||||
const SubnetID id) {
|
||||
Subnet6Ptr subnet = boost::make_shared<Subnet6>
|
||||
(prefix, length, t1, t2, preferred_lifetime, valid_lifetime, id);
|
||||
// IA_NA
|
||||
subnet->setAllocator(Lease::TYPE_NA,
|
||||
boost::make_shared<IterativeAllocator>
|
||||
(Lease::TYPE_NA, subnet));
|
||||
subnet->setAllocationState(Lease::TYPE_NA,
|
||||
SubnetIterativeAllocationState::create(subnet));
|
||||
// IA_TA
|
||||
subnet->setAllocator(Lease::TYPE_TA,
|
||||
boost::make_shared<IterativeAllocator>
|
||||
(Lease::TYPE_TA, subnet));
|
||||
subnet->setAllocationState(Lease::TYPE_TA,
|
||||
SubnetIterativeAllocationState::create(subnet));
|
||||
// IA_PD
|
||||
subnet->setAllocator(Lease::TYPE_PD,
|
||||
boost::make_shared<IterativeAllocator>
|
||||
(Lease::TYPE_PD, subnet));
|
||||
|
||||
subnet->setAllocationState(Lease::TYPE_PD,
|
||||
SubnetIterativeAllocationState::create(subnet));
|
||||
return (subnet);
|
||||
}
|
||||
|
||||
|
@ -290,17 +290,15 @@ public:
|
||||
///
|
||||
/// The actual type of the state depends on the allocator type.
|
||||
///
|
||||
/// @param type lease type for which the allocation state is returned.
|
||||
/// @return allocation state.
|
||||
SubnetAllocationStatePtr getAllocationState() const {
|
||||
return (allocation_state_);
|
||||
}
|
||||
SubnetAllocationStatePtr getAllocationState(Lease::Type type) const;
|
||||
|
||||
/// @brief Sets subnet-specific allocation state.
|
||||
///
|
||||
/// @param type lease type for which the allocation state is set.
|
||||
/// @param allocation_state allocation state instance.
|
||||
void setAllocationState(const SubnetAllocationStatePtr& allocation_state) {
|
||||
allocation_state_ = allocation_state;
|
||||
}
|
||||
void setAllocationState(Lease::Type type, const SubnetAllocationStatePtr& allocation_state);
|
||||
|
||||
protected:
|
||||
|
||||
@ -423,14 +421,14 @@ protected:
|
||||
/// @brief a prefix length of the subnet.
|
||||
uint8_t prefix_len_;
|
||||
|
||||
/// @brief Holds subnet-specific allocation state.
|
||||
SubnetAllocationStatePtr allocation_state_;
|
||||
|
||||
/// @brief Shared network name.
|
||||
std::string shared_network_name_;
|
||||
|
||||
/// @brief Lease allocators used by the subnet.
|
||||
std::map<Lease::Type, AllocatorPtr> allocators_;
|
||||
|
||||
/// @brief Holds subnet-specific allocation state.
|
||||
std::map<Lease::Type, SubnetAllocationStatePtr> allocation_states_;
|
||||
};
|
||||
|
||||
/// @brief A generic pointer to either Subnet4 or Subnet6 object
|
||||
|
@ -32,109 +32,45 @@ public:
|
||||
// Tests initialization of the SubnetAllocationState.
|
||||
TEST(SubnetAllocationState, constructor) {
|
||||
SubnetAllocationState state;
|
||||
EXPECT_TRUE(state.getLastAllocatedTime(Lease::TYPE_V4).is_neg_infinity());
|
||||
EXPECT_TRUE(state.getLastAllocatedTime(Lease::TYPE_NA).is_neg_infinity());
|
||||
EXPECT_TRUE(state.getLastAllocatedTime(Lease::TYPE_TA).is_neg_infinity());
|
||||
EXPECT_TRUE(state.getLastAllocatedTime(Lease::TYPE_PD).is_neg_infinity());
|
||||
EXPECT_TRUE(state.getLastAllocatedTime().is_neg_infinity());
|
||||
}
|
||||
|
||||
// Tests that the explicitly initialized allocation time can be retrieved
|
||||
// for each lease type.
|
||||
// Tests that the explicitly initialized allocation time can be retrieved.
|
||||
TEST(SubnetAllocationState, getLastAllocatedTime) {
|
||||
NakedSubnetAllocationState state;
|
||||
date gdate(greg_year(2002), greg_month(1), greg_day(20));
|
||||
|
||||
time_duration tm_v4(22, 59, 59, 0);
|
||||
ptime time_v4 = ptime(gdate, tm_v4);
|
||||
time_duration t(22, 59, 59, 0);
|
||||
ptime pt = ptime(gdate, t);
|
||||
|
||||
time_duration tm_na(12, 59, 59, 0);
|
||||
ptime time_na = ptime(gdate, tm_na);
|
||||
state.last_allocated_time_= pt;
|
||||
|
||||
time_duration tm_ta(14, 59, 59, 0);
|
||||
ptime time_ta = ptime(gdate, tm_ta);
|
||||
|
||||
time_duration tm_pd(16, 59, 59, 0);
|
||||
ptime time_pd = ptime(gdate, tm_pd);
|
||||
|
||||
state.last_allocated_time_[Lease::TYPE_V4] = time_v4;
|
||||
state.last_allocated_time_[Lease::TYPE_NA] = time_na;
|
||||
state.last_allocated_time_[Lease::TYPE_TA] = time_ta;
|
||||
state.last_allocated_time_[Lease::TYPE_PD] = time_pd;
|
||||
|
||||
EXPECT_EQ(time_v4, state.getLastAllocatedTime(Lease::TYPE_V4));
|
||||
EXPECT_EQ(time_na, state.getLastAllocatedTime(Lease::TYPE_NA));
|
||||
EXPECT_EQ(time_ta, state.getLastAllocatedTime(Lease::TYPE_TA));
|
||||
EXPECT_EQ(time_pd, state.getLastAllocatedTime(Lease::TYPE_PD));
|
||||
EXPECT_EQ(pt, state.getLastAllocatedTime());
|
||||
}
|
||||
|
||||
// Tests that the explicitly initialized allocation time can be retrieved
|
||||
// for each lease type. Multi threaded variant.
|
||||
// Tests that the explicitly initialized allocation time can be retrieved.
|
||||
// Multi threaded variant.
|
||||
TEST(SubnetAllocationState, getLastAllocatedTimeMultiThreading) {
|
||||
MultiThreadingTest mt(true);
|
||||
|
||||
NakedSubnetAllocationState state;
|
||||
date gdate(greg_year(2002), greg_month(1), greg_day(20));
|
||||
|
||||
time_duration tm_v4(22, 59, 59, 0);
|
||||
ptime time_v4 = ptime(gdate, tm_v4);
|
||||
time_duration t(22, 59, 59, 0);
|
||||
ptime pt = ptime(gdate, t);
|
||||
|
||||
time_duration tm_na(12, 59, 59, 0);
|
||||
ptime time_na = ptime(gdate, tm_na);
|
||||
state.last_allocated_time_ = pt;
|
||||
|
||||
time_duration tm_ta(14, 59, 59, 0);
|
||||
ptime time_ta = ptime(gdate, tm_ta);
|
||||
|
||||
time_duration tm_pd(16, 59, 59, 0);
|
||||
ptime time_pd = ptime(gdate, tm_pd);
|
||||
|
||||
state.last_allocated_time_[Lease::TYPE_V4] = time_v4;
|
||||
state.last_allocated_time_[Lease::TYPE_NA] = time_na;
|
||||
state.last_allocated_time_[Lease::TYPE_TA] = time_ta;
|
||||
state.last_allocated_time_[Lease::TYPE_PD] = time_pd;
|
||||
|
||||
EXPECT_EQ(time_v4, state.getLastAllocatedTime(Lease::TYPE_V4));
|
||||
EXPECT_EQ(time_na, state.getLastAllocatedTime(Lease::TYPE_NA));
|
||||
EXPECT_EQ(time_ta, state.getLastAllocatedTime(Lease::TYPE_TA));
|
||||
EXPECT_EQ(time_pd, state.getLastAllocatedTime(Lease::TYPE_PD));
|
||||
EXPECT_EQ(pt, state.getLastAllocatedTime());
|
||||
}
|
||||
|
||||
// Test that current allocation time is set for an IPv4 lease.
|
||||
TEST(SubnetAllocationState, setCurrentAllocatedTimeV4) {
|
||||
// Test that current allocation time is set.
|
||||
TEST(SubnetAllocationState, setCurrentAllocatedTime) {
|
||||
NakedSubnetAllocationState state;
|
||||
|
||||
state.setCurrentAllocatedTimeInternal(Lease::TYPE_V4);
|
||||
auto time_v4 = state.getLastAllocatedTime(Lease::TYPE_V4);
|
||||
auto duration = time_v4 - microsec_clock::universal_time();
|
||||
EXPECT_LT(duration.seconds(), 10);
|
||||
}
|
||||
|
||||
// Test that current allocation time is set for an IPv6 address.
|
||||
TEST(SubnetAllocationState, setCurrentAllocatedTimeNA) {
|
||||
NakedSubnetAllocationState state;
|
||||
|
||||
state.setCurrentAllocatedTimeInternal(Lease::TYPE_NA);
|
||||
auto time_na = state.getLastAllocatedTime(Lease::TYPE_NA);
|
||||
auto duration = time_na - microsec_clock::universal_time();
|
||||
EXPECT_LT(duration.seconds(), 10);
|
||||
}
|
||||
|
||||
// Test that current allocation time is set for an IPv6 temporary address.
|
||||
TEST(SubnetAllocationState, setCurrentAllocatedTimeTA) {
|
||||
NakedSubnetAllocationState state;
|
||||
|
||||
state.setCurrentAllocatedTimeInternal(Lease::TYPE_TA);
|
||||
auto time_ta = state.getLastAllocatedTime(Lease::TYPE_TA);
|
||||
auto duration = time_ta - microsec_clock::universal_time();
|
||||
EXPECT_LT(duration.seconds(), 10);
|
||||
}
|
||||
|
||||
// Test that current allocation time is set for a delegated prefix.
|
||||
TEST(SubnetAllocationState, setCurrentAllocatedTimePD) {
|
||||
NakedSubnetAllocationState state;
|
||||
|
||||
state.setCurrentAllocatedTimeInternal(Lease::TYPE_PD);
|
||||
auto time_pd = state.getLastAllocatedTime(Lease::TYPE_PD);
|
||||
auto duration = time_pd - microsec_clock::universal_time();
|
||||
state.setCurrentAllocatedTimeInternal();
|
||||
auto pt = state.getLastAllocatedTime();
|
||||
auto duration = pt - microsec_clock::universal_time();
|
||||
EXPECT_LT(duration.seconds(), 10);
|
||||
}
|
||||
|
||||
|
@ -2804,7 +2804,7 @@ TEST_F(ParseConfigTest, defaultSubnet4) {
|
||||
EXPECT_TRUE(subnet->getDdnsUseConflictResolution().unspecified());
|
||||
EXPECT_FALSE(subnet->getDdnsUseConflictResolution().get());
|
||||
|
||||
EXPECT_TRUE(subnet->getAllocationState());
|
||||
EXPECT_TRUE(subnet->getAllocationState(Lease::TYPE_V4));
|
||||
EXPECT_TRUE(subnet->getAllocator(Lease::TYPE_V4));
|
||||
|
||||
auto allocator = subnet->getAllocator(Lease::TYPE_V4);
|
||||
@ -2902,10 +2902,9 @@ TEST_F(ParseConfigTest, defaultSubnet6) {
|
||||
EXPECT_TRUE(subnet->getDdnsUseConflictResolution().unspecified());
|
||||
EXPECT_FALSE(subnet->getDdnsUseConflictResolution().get());
|
||||
|
||||
EXPECT_TRUE(subnet->getAllocationState());
|
||||
EXPECT_TRUE(subnet->getAllocator(Lease::TYPE_NA));
|
||||
EXPECT_TRUE(subnet->getAllocator(Lease::TYPE_TA));
|
||||
EXPECT_TRUE(subnet->getAllocator(Lease::TYPE_PD));
|
||||
EXPECT_TRUE(subnet->getAllocationState(Lease::TYPE_NA));
|
||||
EXPECT_TRUE(subnet->getAllocationState(Lease::TYPE_TA));
|
||||
EXPECT_TRUE(subnet->getAllocationState(Lease::TYPE_PD));
|
||||
|
||||
auto allocator = subnet->getAllocator(Lease::TYPE_NA);
|
||||
EXPECT_TRUE(boost::dynamic_pointer_cast<IterativeAllocator>(allocator));
|
||||
@ -3091,6 +3090,12 @@ TEST_F(ParseConfigTest, defaultSharedNetwork6) {
|
||||
|
||||
EXPECT_TRUE(network->getDdnsUseConflictResolution().unspecified());
|
||||
EXPECT_FALSE(network->getDdnsUseConflictResolution().get());
|
||||
|
||||
EXPECT_TRUE(network->getAllocatorType().unspecified());
|
||||
EXPECT_TRUE(network->getAllocatorType().get().empty());
|
||||
|
||||
EXPECT_TRUE(network->getPdAllocatorType().unspecified());
|
||||
EXPECT_TRUE(network->getPdAllocatorType().get().empty());
|
||||
}
|
||||
|
||||
// This test verifies a negative value for the subnet ID is rejected (v4).
|
||||
|
@ -29,11 +29,11 @@ TEST(IterativeAllocationStateTest, subnetLastAllocated4) {
|
||||
auto state = SubnetIterativeAllocationState::create(subnet);
|
||||
|
||||
// Check initial conditions (all should be set to the last address in range)
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_V4).toText());
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated().toText());
|
||||
|
||||
// Now set last allocated for IA
|
||||
EXPECT_NO_THROW(state->setLastAllocated(Lease::TYPE_V4, addr));
|
||||
EXPECT_EQ(addr.toText(), state->getLastAllocated(Lease::TYPE_V4).toText());
|
||||
// Now set last allocated.
|
||||
EXPECT_NO_THROW(state->setLastAllocated(addr));
|
||||
EXPECT_EQ(addr.toText(), state->getLastAllocated().toText());
|
||||
}
|
||||
|
||||
// Checks that the last allocated IPv4 address is remembered in the
|
||||
@ -48,11 +48,11 @@ TEST(IterativeAllocationStateTest, subnetLastAllocated4MultiThreading) {
|
||||
auto state = SubnetIterativeAllocationState::create(subnet);
|
||||
|
||||
// Check initial conditions (all should be set to the last address in range)
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_V4).toText());
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated().toText());
|
||||
|
||||
// Now set last allocated for IA
|
||||
EXPECT_NO_THROW(state->setLastAllocated(Lease::TYPE_V4, addr));
|
||||
EXPECT_EQ(addr.toText(), state->getLastAllocated(Lease::TYPE_V4).toText());
|
||||
// Now set last allocated.
|
||||
EXPECT_NO_THROW(state->setLastAllocated(addr));
|
||||
EXPECT_EQ(addr.toText(), state->getLastAllocated().toText());
|
||||
}
|
||||
|
||||
// Checks if last allocated address/prefix is stored/retrieved properly.
|
||||
@ -63,29 +63,34 @@ TEST(IterativeAllocationStateTest, subnetLastAllocated6) {
|
||||
|
||||
IOAddress last("2001:db8:1::ffff:ffff:ffff:ffff");
|
||||
|
||||
auto subnet = boost::make_shared<Subnet6>(IOAddress("2001:db8:1::"), 64, 1, 2, 3, 4);
|
||||
auto state = SubnetIterativeAllocationState::create(subnet);
|
||||
auto subnet = Subnet6::create(IOAddress("2001:db8:1::"), 64, 1, 2, 3, 4);
|
||||
auto state_na = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet->getAllocationState(Lease::TYPE_NA));
|
||||
auto state_ta = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet->getAllocationState(Lease::TYPE_TA));
|
||||
auto state_pd = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet->getAllocationState(Lease::TYPE_PD));
|
||||
|
||||
// Check initial conditions (all should be set to the last address in range)
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_NA).toText());
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_TA).toText());
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_PD).toText());
|
||||
EXPECT_EQ(last.toText(), state_na->getLastAllocated().toText());
|
||||
EXPECT_EQ(last.toText(), state_ta->getLastAllocated().toText());
|
||||
EXPECT_EQ(last.toText(), state_pd->getLastAllocated().toText());
|
||||
|
||||
// Now set last allocated for IA
|
||||
EXPECT_NO_THROW(state->setLastAllocated(Lease::TYPE_NA, na));
|
||||
EXPECT_EQ(na.toText(), state->getLastAllocated(Lease::TYPE_NA).toText());
|
||||
EXPECT_NO_THROW(state_na->setLastAllocated(na));
|
||||
EXPECT_EQ(na.toText(), state_na->getLastAllocated().toText());
|
||||
|
||||
// TA and PD should be unchanged
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_TA).toText());
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_PD).toText());
|
||||
EXPECT_EQ(last.toText(), state_ta->getLastAllocated().toText());
|
||||
EXPECT_EQ(last.toText(), state_pd->getLastAllocated().toText());
|
||||
|
||||
// Now set TA and PD
|
||||
EXPECT_NO_THROW(state->setLastAllocated(Lease::TYPE_TA, ta));
|
||||
EXPECT_NO_THROW(state->setLastAllocated(Lease::TYPE_PD, pd));
|
||||
EXPECT_NO_THROW(state_ta->setLastAllocated(ta));
|
||||
EXPECT_NO_THROW(state_pd->setLastAllocated(pd));
|
||||
|
||||
EXPECT_EQ(na.toText(), state->getLastAllocated(Lease::TYPE_NA).toText());
|
||||
EXPECT_EQ(ta.toText(), state->getLastAllocated(Lease::TYPE_TA).toText());
|
||||
EXPECT_EQ(pd.toText(), state->getLastAllocated(Lease::TYPE_PD).toText());
|
||||
EXPECT_EQ(na.toText(), state_na->getLastAllocated().toText());
|
||||
EXPECT_EQ(ta.toText(), state_ta->getLastAllocated().toText());
|
||||
EXPECT_EQ(pd.toText(), state_pd->getLastAllocated().toText());
|
||||
}
|
||||
|
||||
// Checks if last allocated address/prefix is stored/retrieved properly when
|
||||
@ -98,29 +103,34 @@ TEST(IterativeAllocationStateTest, subnetLastAllocated6MultiThreading) {
|
||||
|
||||
IOAddress last("2001:db8:1::ffff:ffff:ffff:ffff");
|
||||
|
||||
auto subnet = boost::make_shared<Subnet6>(IOAddress("2001:db8:1::"), 64, 1, 2, 3, 4);
|
||||
auto state = SubnetIterativeAllocationState::create(subnet);
|
||||
auto subnet = Subnet6::create(IOAddress("2001:db8:1::"), 64, 1, 2, 3, 4);
|
||||
auto state_na = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet->getAllocationState(Lease::TYPE_NA));
|
||||
auto state_ta = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet->getAllocationState(Lease::TYPE_TA));
|
||||
auto state_pd = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet->getAllocationState(Lease::TYPE_PD));
|
||||
|
||||
// Check initial conditions (all should be set to the last address in range)
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_NA).toText());
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_TA).toText());
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_PD).toText());
|
||||
EXPECT_EQ(last.toText(), state_na->getLastAllocated().toText());
|
||||
EXPECT_EQ(last.toText(), state_ta->getLastAllocated().toText());
|
||||
EXPECT_EQ(last.toText(), state_pd->getLastAllocated().toText());
|
||||
|
||||
// Now set last allocated for IA
|
||||
EXPECT_NO_THROW(state->setLastAllocated(Lease::TYPE_NA, na));
|
||||
EXPECT_EQ(na.toText(), state->getLastAllocated(Lease::TYPE_NA).toText());
|
||||
EXPECT_NO_THROW(state_na->setLastAllocated(na));
|
||||
EXPECT_EQ(na.toText(), state_na->getLastAllocated().toText());
|
||||
|
||||
// TA and PD should be unchanged
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_TA).toText());
|
||||
EXPECT_EQ(last.toText(), state->getLastAllocated(Lease::TYPE_PD).toText());
|
||||
EXPECT_EQ(last.toText(), state_ta->getLastAllocated().toText());
|
||||
EXPECT_EQ(last.toText(), state_pd->getLastAllocated().toText());
|
||||
|
||||
// Now set TA and PD
|
||||
EXPECT_NO_THROW(state->setLastAllocated(Lease::TYPE_TA, ta));
|
||||
EXPECT_NO_THROW(state->setLastAllocated(Lease::TYPE_PD, pd));
|
||||
EXPECT_NO_THROW(state_ta->setLastAllocated(ta));
|
||||
EXPECT_NO_THROW(state_pd->setLastAllocated(pd));
|
||||
|
||||
EXPECT_EQ(na.toText(), state->getLastAllocated(Lease::TYPE_NA).toText());
|
||||
EXPECT_EQ(ta.toText(), state->getLastAllocated(Lease::TYPE_TA).toText());
|
||||
EXPECT_EQ(pd.toText(), state->getLastAllocated(Lease::TYPE_PD).toText());
|
||||
EXPECT_EQ(na.toText(), state_na->getLastAllocated().toText());
|
||||
EXPECT_EQ(ta.toText(), state_ta->getLastAllocated().toText());
|
||||
EXPECT_EQ(pd.toText(), state_pd->getLastAllocated().toText());
|
||||
}
|
||||
|
||||
// Checks that last allocated IPv4 address is stored in the pool-specific
|
||||
|
@ -293,7 +293,7 @@ TEST_F(IterativeAllocatorTest6, addrStepOutClass) {
|
||||
// This test verifies that the allocator picks delegated prefixes from several
|
||||
// pools.
|
||||
TEST_F(IterativeAllocatorTest6, prefixStep) {
|
||||
subnet_.reset(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));
|
||||
subnet_ = Subnet6::create(IOAddress("2001:db8::"), 32, 1, 2, 3, 4);
|
||||
|
||||
Pool6Ptr pool1(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 56, 60));
|
||||
Pool6Ptr pool2(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1::"), 48, 48));
|
||||
@ -372,7 +372,7 @@ TEST_F(IterativeAllocatorTest6, prefixStep) {
|
||||
// This test verifies that the allocator picks delegated prefixes from the pools
|
||||
// with class guards.
|
||||
TEST_F(IterativeAllocatorTest6, prefixStepInClass) {
|
||||
subnet_.reset(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));
|
||||
subnet_ = Subnet6::create(IOAddress("2001:db8::"), 32, 1, 2, 3, 4);
|
||||
|
||||
Pool6Ptr pool1(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 56, 60));
|
||||
Pool6Ptr pool2(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1::"), 48, 48));
|
||||
@ -456,7 +456,7 @@ TEST_F(IterativeAllocatorTest6, prefixStepInClass) {
|
||||
|
||||
// This test verifies that the allocator omits pools with non-matching client classes.
|
||||
TEST_F(IterativeAllocatorTest6, prefixStepOutClass) {
|
||||
subnet_.reset(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));
|
||||
subnet_ = Subnet6::create(IOAddress("2001:db8::"), 32, 1, 2, 3, 4);
|
||||
|
||||
Pool6Ptr pool1(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 56, 60));
|
||||
Pool6Ptr pool2(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1::"), 48, 48));
|
||||
|
@ -378,6 +378,8 @@ TEST_F(NetworkTest, inheritanceSupport6) {
|
||||
globals_->set("store-extended-info", Element::create(true));
|
||||
globals_->set("ddns-update-on-renew", Element::create(true));
|
||||
globals_->set("ddns-use-conflict-resolution", Element::create(true));
|
||||
globals_->set("allocator", Element::create("random"));
|
||||
globals_->set("pd-allocator", Element::create("random"));
|
||||
|
||||
// For each parameter for which inheritance is supported run
|
||||
// the test that checks if the values are inherited properly.
|
||||
@ -456,6 +458,18 @@ TEST_F(NetworkTest, inheritanceSupport6) {
|
||||
&Network6::setDdnsUseConflictResolution,
|
||||
false, true);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("allocator");
|
||||
testNetworkInheritance<TestNetwork6>(&Network6::getAllocatorType,
|
||||
&Network6::setAllocatorType,
|
||||
"iterative", "random");
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("pd-allocator");
|
||||
testNetworkInheritance<TestNetwork6>(&Network6::getPdAllocatorType,
|
||||
&Network6::setPdAllocatorType,
|
||||
"iterative", "random");
|
||||
}
|
||||
|
||||
// Interface-id requires special type of test.
|
||||
boost::shared_ptr<TestNetwork6> net_child(new TestNetwork6());
|
||||
|
@ -390,24 +390,15 @@ TEST(SharedNetwork4Test, getPreferredSubnet) {
|
||||
SharedNetwork4Ptr network(new SharedNetwork4("frog"));
|
||||
|
||||
// Create four subnets.
|
||||
Subnet4Ptr subnet1(new Subnet4(IOAddress("10.0.0.0"), 8, 10, 20, 30,
|
||||
SubnetID(1)));
|
||||
Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.0"), 24, 10, 20, 30,
|
||||
SubnetID(2)));
|
||||
Subnet4Ptr subnet3(new Subnet4(IOAddress("172.16.25.0"), 24, 10, 20, 30,
|
||||
SubnetID(3)));
|
||||
Subnet4Ptr subnet4(new Subnet4(IOAddress("172.16.28.0"), 24, 10, 20, 30,
|
||||
SubnetID(4)));
|
||||
auto subnet1 = Subnet4::create(IOAddress("10.0.0.0"), 8, 10, 20, 30,
|
||||
SubnetID(1));
|
||||
auto subnet2 = Subnet4::create(IOAddress("192.0.2.0"), 24, 10, 20, 30,
|
||||
SubnetID(2));
|
||||
auto subnet3 = Subnet4::create(IOAddress("172.16.25.0"), 24, 10, 20, 30,
|
||||
SubnetID(3));
|
||||
auto subnet4 = Subnet4::create(IOAddress("172.16.28.0"), 24, 10, 20, 30,
|
||||
SubnetID(4));
|
||||
|
||||
auto state1 = SubnetIterativeAllocationState::create(subnet1);
|
||||
auto state2 = SubnetIterativeAllocationState::create(subnet2);
|
||||
auto state3 = SubnetIterativeAllocationState::create(subnet3);
|
||||
auto state4 = SubnetIterativeAllocationState::create(subnet4);
|
||||
|
||||
subnet1->setAllocationState(state1);
|
||||
subnet2->setAllocationState(state2);
|
||||
subnet3->setAllocationState(state3);
|
||||
subnet4->setAllocationState(state4);
|
||||
|
||||
// Associate first two subnets with classes.
|
||||
subnet1->allowClientClass("class1");
|
||||
@ -438,7 +429,9 @@ TEST(SharedNetwork4Test, getPreferredSubnet) {
|
||||
|
||||
// Allocating an address from subnet2 updates the last allocated timestamp
|
||||
// for this subnet, which makes this subnet preferred over subnet1.
|
||||
state2->setLastAllocated(Lease::TYPE_V4, IOAddress("192.0.2.25"));
|
||||
auto state2 = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet2->getAllocationState(Lease::TYPE_V4));
|
||||
state2->setLastAllocated(IOAddress("192.0.2.25"));
|
||||
preferred = network->getPreferredSubnet(subnet1);
|
||||
EXPECT_EQ(subnet2->getID(), preferred->getID());
|
||||
|
||||
@ -458,7 +451,9 @@ TEST(SharedNetwork4Test, getPreferredSubnet) {
|
||||
|
||||
// Allocate an address from the subnet3. This makes it preferred to
|
||||
// subnet4.
|
||||
state3->setLastAllocated(Lease::TYPE_V4, IOAddress("172.16.25.23"));
|
||||
auto state3 = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet3->getAllocationState(Lease::TYPE_V4));
|
||||
state3->setLastAllocated(IOAddress("172.16.25.23"));
|
||||
|
||||
// If the selected is subnet1, the preferred subnet is subnet2, because
|
||||
// it has the same set of classes as subnet1. The subnet3 can't be
|
||||
@ -483,24 +478,14 @@ TEST(SharedNetwork4Test, getPreferredSubnetMultiThreading) {
|
||||
SharedNetwork4Ptr network(new SharedNetwork4("frog"));
|
||||
|
||||
// Create four subnets.
|
||||
Subnet4Ptr subnet1(new Subnet4(IOAddress("10.0.0.0"), 8, 10, 20, 30,
|
||||
SubnetID(1)));
|
||||
Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.0"), 24, 10, 20, 30,
|
||||
SubnetID(2)));
|
||||
Subnet4Ptr subnet3(new Subnet4(IOAddress("172.16.25.0"), 24, 10, 20, 30,
|
||||
SubnetID(3)));
|
||||
Subnet4Ptr subnet4(new Subnet4(IOAddress("172.16.28.0"), 24, 10, 20, 30,
|
||||
SubnetID(4)));
|
||||
|
||||
auto state1 = SubnetIterativeAllocationState::create(subnet1);
|
||||
auto state2 = SubnetIterativeAllocationState::create(subnet2);
|
||||
auto state3 = SubnetIterativeAllocationState::create(subnet3);
|
||||
auto state4 = SubnetIterativeAllocationState::create(subnet4);
|
||||
|
||||
subnet1->setAllocationState(state1);
|
||||
subnet2->setAllocationState(state2);
|
||||
subnet3->setAllocationState(state3);
|
||||
subnet4->setAllocationState(state4);
|
||||
auto subnet1 = Subnet4::create(IOAddress("10.0.0.0"), 8, 10, 20, 30,
|
||||
SubnetID(1));
|
||||
auto subnet2 = Subnet4::create(IOAddress("192.0.2.0"), 24, 10, 20, 30,
|
||||
SubnetID(2));
|
||||
auto subnet3 = Subnet4::create(IOAddress("172.16.25.0"), 24, 10, 20, 30,
|
||||
SubnetID(3));
|
||||
auto subnet4 = Subnet4::create(IOAddress("172.16.28.0"), 24, 10, 20, 30,
|
||||
SubnetID(4));
|
||||
|
||||
// Associate first two subnets with classes.
|
||||
subnet1->allowClientClass("class1");
|
||||
@ -530,8 +515,10 @@ TEST(SharedNetwork4Test, getPreferredSubnetMultiThreading) {
|
||||
}
|
||||
|
||||
// Allocating an address from subnet2 updates the last allocated timestamp
|
||||
// for this subnet, which makes this subnet preferred over subnet1.
|
||||
state2->setLastAllocated(Lease::TYPE_V4, IOAddress("192.0.2.25"));
|
||||
// for this subnet, which makes this subnet preferred over subnet1
|
||||
auto state2 = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet2->getAllocationState(Lease::TYPE_V4));
|
||||
state2->setLastAllocated(IOAddress("192.0.2.25"));
|
||||
preferred = network->getPreferredSubnet(subnet1);
|
||||
EXPECT_EQ(subnet2->getID(), preferred->getID());
|
||||
|
||||
@ -551,7 +538,9 @@ TEST(SharedNetwork4Test, getPreferredSubnetMultiThreading) {
|
||||
|
||||
// Allocate an address from the subnet3. This makes it preferred to
|
||||
// subnet4.
|
||||
state3->setLastAllocated(Lease::TYPE_V4, IOAddress("172.16.25.23"));
|
||||
auto state3 = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet3->getAllocationState(Lease::TYPE_V4));
|
||||
state3->setLastAllocated(IOAddress("172.16.25.23"));
|
||||
|
||||
// If the selected is subnet1, the preferred subnet is subnet2, because
|
||||
// it has the same set of classes as subnet1. The subnet3 can't be
|
||||
@ -1125,24 +1114,14 @@ TEST(SharedNetwork6Test, getPreferredSubnet) {
|
||||
SharedNetwork6Ptr network(new SharedNetwork6("frog"));
|
||||
|
||||
// Create four subnets.
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 64, 10, 20, 30,
|
||||
40, SubnetID(1)));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 16, 10, 20, 30, 40,
|
||||
SubnetID(2)));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:2::"), 64, 10, 20, 30,
|
||||
40, SubnetID(3)));
|
||||
Subnet6Ptr subnet4(new Subnet6(IOAddress("3000:1::"), 64, 10, 20, 30,
|
||||
40, SubnetID(4)));
|
||||
|
||||
auto state1 = SubnetIterativeAllocationState::create(subnet1);
|
||||
auto state2 = SubnetIterativeAllocationState::create(subnet2);
|
||||
auto state3 = SubnetIterativeAllocationState::create(subnet3);
|
||||
auto state4 = SubnetIterativeAllocationState::create(subnet4);
|
||||
|
||||
subnet1->setAllocationState(state1);
|
||||
subnet2->setAllocationState(state2);
|
||||
subnet3->setAllocationState(state3);
|
||||
subnet4->setAllocationState(state4);
|
||||
auto subnet1 = Subnet6::create(IOAddress("2001:db8:1::"), 64, 10, 20, 30,
|
||||
40, SubnetID(1));
|
||||
auto subnet2 = Subnet6::create(IOAddress("3000::"), 16, 10, 20, 30, 40,
|
||||
SubnetID(2));
|
||||
auto subnet3 = Subnet6::create(IOAddress("2001:db8:2::"), 64, 10, 20, 30,
|
||||
40, SubnetID(3));
|
||||
auto subnet4 = Subnet6::create(IOAddress("3000:1::"), 64, 10, 20, 30,
|
||||
40, SubnetID(4));
|
||||
|
||||
// Associate first two subnets with classes.
|
||||
subnet1->allowClientClass("class1");
|
||||
@ -1176,8 +1155,10 @@ TEST(SharedNetwork6Test, getPreferredSubnet) {
|
||||
}
|
||||
|
||||
// Allocating an address from subnet2 updates the last allocated timestamp
|
||||
// for this subnet, which makes this subnet preferred over subnet1.
|
||||
state2->setLastAllocated(Lease::TYPE_NA, IOAddress("2001:db8:1:2::"));
|
||||
// for this subnet, which makes this subnet preferred over subnet1
|
||||
auto state = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet2->getAllocationState(Lease::TYPE_NA));
|
||||
state->setLastAllocated(IOAddress("2001:db8:1:2::"));
|
||||
preferred = network->getPreferredSubnet(subnet1, Lease::TYPE_NA);
|
||||
EXPECT_EQ(subnet2->getID(), preferred->getID());
|
||||
|
||||
@ -1192,7 +1173,9 @@ TEST(SharedNetwork6Test, getPreferredSubnet) {
|
||||
|
||||
// Although, if we pick a prefix from the subnet2, we should get the
|
||||
// subnet2 as preferred instead.
|
||||
state2->setLastAllocated(Lease::TYPE_PD, IOAddress("3000:1234::"));
|
||||
state = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet2->getAllocationState(Lease::TYPE_PD));
|
||||
state->setLastAllocated(IOAddress("3000:1234::"));
|
||||
preferred = network->getPreferredSubnet(subnet1, Lease::TYPE_PD);
|
||||
EXPECT_EQ(subnet2->getID(), preferred->getID());
|
||||
|
||||
@ -1208,7 +1191,9 @@ TEST(SharedNetwork6Test, getPreferredSubnet) {
|
||||
|
||||
// Allocate an address from the subnet3. This makes it preferred to
|
||||
// subnet4.
|
||||
state3->setLastAllocated(Lease::TYPE_NA, IOAddress("2001:db8:2:1234::"));
|
||||
state = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet3->getAllocationState(Lease::TYPE_NA));
|
||||
state->setLastAllocated(IOAddress("2001:db8:2:1234::"));
|
||||
|
||||
// If the selected is subnet1, the preferred subnet is subnet2, because
|
||||
// it has the same set of classes as subnet1. The subnet3 can't be
|
||||
@ -1233,24 +1218,14 @@ TEST(SharedNetwork6Test, getPreferredSubnetMultiThreading) {
|
||||
SharedNetwork6Ptr network(new SharedNetwork6("frog"));
|
||||
|
||||
// Create four subnets.
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 64, 10, 20, 30,
|
||||
40, SubnetID(1)));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 16, 10, 20, 30, 40,
|
||||
SubnetID(2)));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:2::"), 64, 10, 20, 30,
|
||||
40, SubnetID(3)));
|
||||
Subnet6Ptr subnet4(new Subnet6(IOAddress("3000:1::"), 64, 10, 20, 30,
|
||||
40, SubnetID(4)));
|
||||
|
||||
auto state1 = SubnetIterativeAllocationState::create(subnet1);
|
||||
auto state2 = SubnetIterativeAllocationState::create(subnet2);
|
||||
auto state3 = SubnetIterativeAllocationState::create(subnet3);
|
||||
auto state4 = SubnetIterativeAllocationState::create(subnet4);
|
||||
|
||||
subnet1->setAllocationState(state1);
|
||||
subnet2->setAllocationState(state2);
|
||||
subnet3->setAllocationState(state3);
|
||||
subnet4->setAllocationState(state4);
|
||||
auto subnet1 = Subnet6::create(IOAddress("2001:db8:1::"), 64, 10, 20, 30,
|
||||
40, SubnetID(1));
|
||||
auto subnet2 = Subnet6::create(IOAddress("3000::"), 16, 10, 20, 30, 40,
|
||||
SubnetID(2));
|
||||
auto subnet3 = Subnet6::create(IOAddress("2001:db8:2::"), 64, 10, 20, 30,
|
||||
40, SubnetID(3));
|
||||
auto subnet4 = Subnet6::create(IOAddress("3000:1::"), 64, 10, 20, 30,
|
||||
40, SubnetID(4));
|
||||
|
||||
// Associate first two subnets with classes.
|
||||
subnet1->allowClientClass("class1");
|
||||
@ -1285,7 +1260,9 @@ TEST(SharedNetwork6Test, getPreferredSubnetMultiThreading) {
|
||||
|
||||
// Allocating an address from subnet2 updates the last allocated timestamp
|
||||
// for this subnet, which makes this subnet preferred over subnet1.
|
||||
state2->setLastAllocated(Lease::TYPE_NA, IOAddress("2001:db8:1:2::"));
|
||||
auto state = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet2->getAllocationState(Lease::TYPE_NA));
|
||||
state->setLastAllocated(IOAddress("2001:db8:1:2::"));
|
||||
preferred = network->getPreferredSubnet(subnet1, Lease::TYPE_NA);
|
||||
EXPECT_EQ(subnet2->getID(), preferred->getID());
|
||||
|
||||
@ -1300,7 +1277,9 @@ TEST(SharedNetwork6Test, getPreferredSubnetMultiThreading) {
|
||||
|
||||
// Although, if we pick a prefix from the subnet2, we should get the
|
||||
// subnet2 as preferred instead.
|
||||
state2->setLastAllocated(Lease::TYPE_PD, IOAddress("3000:1234::"));
|
||||
state = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet2->getAllocationState(Lease::TYPE_PD));
|
||||
state->setLastAllocated(IOAddress("3000:1234::"));
|
||||
preferred = network->getPreferredSubnet(subnet1, Lease::TYPE_PD);
|
||||
EXPECT_EQ(subnet2->getID(), preferred->getID());
|
||||
|
||||
@ -1316,7 +1295,9 @@ TEST(SharedNetwork6Test, getPreferredSubnetMultiThreading) {
|
||||
|
||||
// Allocate an address from the subnet3. This makes it preferred to
|
||||
// subnet4.
|
||||
state3->setLastAllocated(Lease::TYPE_NA, IOAddress("2001:db8:2:1234::"));
|
||||
state = boost::dynamic_pointer_cast<SubnetIterativeAllocationState>
|
||||
(subnet3->getAllocationState(Lease::TYPE_NA));
|
||||
state->setLastAllocated(IOAddress("2001:db8:2:1234::"));
|
||||
|
||||
// If the selected is subnet1, the preferred subnet is subnet2, because
|
||||
// it has the same set of classes as subnet1. The subnet3 can't be
|
||||
|
Loading…
x
Reference in New Issue
Block a user