2
0
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:
Marcin Siodelski 2022-11-21 12:13:01 +01:00
parent 9571b8f80b
commit d92cc17a20
34 changed files with 5744 additions and 4842 deletions

View File

@ -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.

View File

@ -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"

View File

@ -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"

View File

@ -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
;

View File

@ -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

View File

@ -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

View File

@ -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
;

View File

@ -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

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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.

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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).

View File

@ -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

View File

@ -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));

View File

@ -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());

View File

@ -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