Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
Kea
Commits
e50fd180
Commit
e50fd180
authored
Sep 28, 2015
by
Marcin Siodelski
Browse files
[3972] Lease reclamation routine executes the callouts.
parent
dde7523e
Changes
6
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/dhcp4_hooks.dox
View file @
e50fd180
...
...
@@ -217,5 +217,33 @@ packet processing. Hook points that are not specific to packet processing
(e.g. lease was allocated). Setting this flag merely stops the change
being communicated to the client.
@subsection dhcpv4HooksLease4Expire lease4_expire
- @b Arguments:
- name: @b lease4, type: isc::dhcp::Lease4Ptr, direction: <b>in/out</b>
- name: @b remove_lease, type: bool, direction: <b>in</b>
- @b Description: this callout is executed for each expired lease when
the server performs reclamation of the expired leases. During this
process the server executes "lease4_expire" callout, removes the DNS
records associated with this lease and finally removes the lease from
the database or updates its status to "expired-reclaimed". The "lease4"
argument contains the pointer to the lease being reclaimed. The second
argument "remove_lease" indicates if the reclaimed leases should be
removed from the lease database (if true), or their state should be
set to "expired-reclaimed" in the lease database. This parameter
is only used by the callout if it takes responsibility for the lease
reclamation, i.e. it sets the "skip" flag to "true".
- <b>Skip flag action</b>: if the callout sets the skip flag, the server
will assume that the callout has fully reclaimed the lease, i.e.
performed the DNS update and updated the lease in the database. The
server will not perform any further actions on the lease for which the
skip flag has been set. It is important to note that if the callout
sets this flag but fails to reclaim the lease in the database, the
reclamation routine will repeatedly process this lease in subsequent
runs. Therefore, the implementors of this callout must make sure that
skip flag is only set when the lease has been actually reclaimed in the
database by the callout.
*/
src/bin/dhcp6/dhcp6_hooks.dox
View file @
e50fd180
...
...
@@ -235,4 +235,33 @@ packet processing. Hook points that are not specific to packet processing
(e.g. lease was allocated). Setting this flag merely stops the change
being communicated to the client.
@subsection dhcpv6HooksLease6Expire lease6_expire
- @b Arguments:
- name: @b lease6, type: isc::dhcp::Lease6Ptr, direction: <b>in/out</b>
- name: @b remove_lease, type: bool, direction: <b>in</b>
- @b Description: this callout is executed for each expired lease when
the server performs reclamation of the expired leases. During this
process the server executes "lease6_expire" callout, removes the DNS
records associated with this lease and finally removes the lease from
the database or updates its status to "expired-reclaimed". The "lease6"
argument contains the pointer to the lease being reclaimed. The second
argument "remove_lease" indicates if the reclaimed leases should be
removed from the lease database (if true), or their state should be
set to "expired-reclaimed" in the lease database. This parameter
is only used by the callout if it takes responsibility for the lease
reclamation, i.e. it sets the "skip" flag to "true".
- <b>Skip flag action</b>: if the callout sets the skip flag, the server
will assume that the callout has fully reclaimed the lease, i.e.
performed the DNS update and updated the lease in the database. The
server will not perform any further actions on the lease for which the
skip flag has been set. It is important to note that if the callout
sets this flag but fails to reclaim the lease in the database, the
reclamation routine will repeatedly process this lease in subsequent
runs. Therefore, the implementors of this callout must make sure that
skip flag is only set when the lease has been actually reclaimed in the
database by the callout.
*/
src/lib/dhcpsrv/alloc_engine.cc
View file @
e50fd180
...
...
@@ -25,6 +25,8 @@
#include
<dhcpsrv/host.h>
#include
<dhcpsrv/lease_mgr_factory.h>
#include
<dhcp/dhcp6.h>
#include
<hooks/callout_handle.h>
#include
<hooks/hooks_manager.h>
#include
<stats/stats_mgr.h>
#include
<util/stopwatch.h>
#include
<hooks/server_hooks.h>
...
...
@@ -51,17 +53,21 @@ namespace {
struct
AllocEngineHooks
{
int
hook_index_lease4_select_
;
///< index for "lease4_receive" hook point
int
hook_index_lease4_renew_
;
///< index for "lease4_renew" hook point
int
hook_index_lease4_expire_
;
///< index for "lease4_expire" hook point
int
hook_index_lease6_select_
;
///< index for "lease6_receive" hook point
int
hook_index_lease6_renew_
;
///< index for "lease6_renew" hook point
int
hook_index_lease6_rebind_
;
///< index for "lease6_rebind" hook point
int
hook_index_lease6_expire_
;
///< index for "lease6_expire" hook point
/// Constructor that registers hook points for AllocationEngine
AllocEngineHooks
()
{
hook_index_lease4_select_
=
HooksManager
::
registerHook
(
"lease4_select"
);
hook_index_lease4_renew_
=
HooksManager
::
registerHook
(
"lease4_renew"
);
hook_index_lease4_expire_
=
HooksManager
::
registerHook
(
"lease4_expire"
);
hook_index_lease6_select_
=
HooksManager
::
registerHook
(
"lease6_select"
);
hook_index_lease6_renew_
=
HooksManager
::
registerHook
(
"lease6_renew"
);
hook_index_lease6_rebind_
=
HooksManager
::
registerHook
(
"lease6_rebind"
);
hook_index_lease6_renew_
=
HooksManager
::
registerHook
(
"lease6_renew"
);
hook_index_lease6_rebind_
=
HooksManager
::
registerHook
(
"lease6_rebind"
);
hook_index_lease6_expire_
=
HooksManager
::
registerHook
(
"lease6_expire"
);
}
};
...
...
@@ -1291,8 +1297,6 @@ AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeo
// Create stopwatch and automatically start it to measure the time
// taken by the routine.
/// @todo Monitor time elapsed and return from the lease reclamation routine
/// if it hits the timeout value.
util
::
Stopwatch
stopwatch
;
LeaseMgr
&
lease_mgr
=
LeaseMgrFactory
::
instance
();
...
...
@@ -1300,23 +1304,50 @@ AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeo
Lease6Collection
leases
;
lease_mgr
.
getExpiredLeases6
(
leases
,
max_leases
);
// Do not initialize the callout handle until we know if there are any
// lease6_expire callouts installed.
CalloutHandlePtr
callout_handle
;
if
(
!
leases
.
empty
()
&&
HooksManager
::
getHooksManager
().
calloutsPresent
(
Hooks
.
hook_index_lease6_expire_
))
{
callout_handle
=
HooksManager
::
createCalloutHandle
();
}
size_t
leases_processed
=
0
;
BOOST_FOREACH
(
Lease6Ptr
lease
,
leases
)
{
try
{
/// @todo execute a lease6_expire hook here.
// The skip flag indicates if the callouts have taken responsibility
// for reclaiming the lease. The callout will set this to true if
// it reclaims the lease itself. In this case the reclamation routine
// will not update DNS nor update the database.
bool
skipped
=
false
;
if
(
callout_handle
)
{
callout_handle
->
deleteAllArguments
();
callout_handle
->
setArgument
(
"lease6"
,
lease
);
callout_handle
->
setArgument
(
"remove_lease"
,
remove_lease
);
HooksManager
::
callCallouts
(
Hooks
.
hook_index_lease6_expire_
,
*
callout_handle
);
skipped
=
callout_handle
->
getSkip
();
}
if
(
!
skipped
)
{
// Generate removal name change request for D2, if required.
// This will return immediatelly if the DNS wasn't updated
// when the lease was created.
if
(
lease
->
duid_
)
{
queueRemovalNameChangeRequest
(
lease
,
*
(
lease
->
duid_
));
}
// Generate removal name change request for D2, if required.
// This will return immediatelly if the DNS wasn't updated
// when the lease was created.
if
(
lease
->
duid_
)
{
queueRemovalNameChangeRequest
(
lease
,
*
(
lease
->
duid_
));
// Reclaim the lease - depending on the configuration, set the
// expired-reclaimed state or simply remove it.
reclaimLeaseInDatabase
<
Lease6Ptr
>
(
lease
,
remove_lease
,
boost
::
bind
(
&
LeaseMgr
::
updateLease6
,
&
lease_mgr
,
_1
));
}
// Reclaim the lease - depending on the configuration, set the
// expired-reclaimed state or simply remove it.
reclaimLeaseInDatabase
<
Lease6Ptr
>
(
lease
,
remove_lease
,
boost
::
bind
(
&
LeaseMgr
::
updateLease6
,
&
lease_mgr
,
_1
));
++
leases_processed
;
// Update statistics.
...
...
@@ -1352,6 +1383,16 @@ AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeo
.
arg
(
lease
->
addr_
.
toText
())
.
arg
(
ex
.
what
());
}
// Check if we have hit the timeout for running reclamation routine and
// return if we have. We're checking it here, because we always want to
// allow reclaiming at least one lease.
if
((
timeout
>
0
)
&&
(
stopwatch
.
getTotalMilliseconds
()
>=
timeout
))
{
LOG_DEBUG
(
alloc_engine_logger
,
ALLOC_ENGINE_DBG_TRACE
,
ALLOC_ENGINE_V6_LEASES_RECLAMATION_TIMEOUT
)
.
arg
(
timeout
);
break
;
}
}
// Stop measuring the time.
...
...
@@ -1360,7 +1401,7 @@ AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeo
// Mark completion of the lease reclamation routine and present some stats.
LOG_DEBUG
(
alloc_engine_logger
,
ALLOC_ENGINE_DBG_TRACE
,
ALLOC_ENGINE_V6_LEASES_RECLAMATION_COMPLETE
)
.
arg
(
leases
.
size
()
)
.
arg
(
leases
_processed
)
.
arg
(
stopwatch
.
logFormatTotalDuration
());
}
...
...
@@ -1375,8 +1416,6 @@ AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeo
// Create stopwatch and automatically start it to measure the time
// taken by the routine.
/// @todo Monitor time elapsed and return from the lease reclamation routine
/// if it hits the timeout value.
util
::
Stopwatch
stopwatch
;
LeaseMgr
&
lease_mgr
=
LeaseMgrFactory
::
instance
();
...
...
@@ -1384,29 +1423,56 @@ AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeo
Lease4Collection
leases
;
lease_mgr
.
getExpiredLeases4
(
leases
,
max_leases
);
// Do not initialize the callout handle until we know if there are any
// lease6_expire callouts installed.
CalloutHandlePtr
callout_handle
;
if
(
!
leases
.
empty
()
&&
HooksManager
::
getHooksManager
().
calloutsPresent
(
Hooks
.
hook_index_lease4_expire_
))
{
callout_handle
=
HooksManager
::
createCalloutHandle
();
}
size_t
leases_processed
=
0
;
BOOST_FOREACH
(
Lease4Ptr
lease
,
leases
)
{
try
{
/// @todo execute a lease4_expire hook here.
// The skip flag indicates if the callouts have taken responsibility
// for reclaiming the lease. The callout will set this to true if
// it reclaims the lease itself. In this case the reclamation routine
// will not update DNS nor update the database.
bool
skipped
=
false
;
if
(
callout_handle
)
{
callout_handle
->
deleteAllArguments
();
callout_handle
->
setArgument
(
"lease4"
,
lease
);
callout_handle
->
setArgument
(
"remove_lease"
,
remove_lease
);
HooksManager
::
callCallouts
(
Hooks
.
hook_index_lease4_expire_
,
*
callout_handle
);
skipped
=
callout_handle
->
getSkip
();
}
// Generate removal name change request for D2, if required.
// This will return immediatelly if the DNS wasn't updated
// when the lease was created.
if
(
lease
->
client_id_
)
{
// Client id takes precedence over HW address.
queueRemovalNameChangeRequest
(
lease
,
lease
->
client_id_
->
getClientId
());
if
(
!
skipped
)
{
// Generate removal name change request for D2, if required.
// This will return immediatelly if the DNS wasn't updated
// when the lease was created.
if
(
lease
->
client_id_
)
{
// Client id takes precedence over HW address.
queueRemovalNameChangeRequest
(
lease
,
lease
->
client_id_
->
getClientId
());
}
else
{
// Client id is not specified for the lease. Use HW address
// instead.
queueRemovalNameChangeRequest
(
lease
,
lease
->
hwaddr_
);
}
else
{
// Client id is not specified for the lease. Use HW address
// instead.
queueRemovalNameChangeRequest
(
lease
,
lease
->
hwaddr_
);
}
// Reclaim the lease - depending on the configuration, set the
// expired-reclaimed state or simply remove it.
reclaimLeaseInDatabase
<
Lease4Ptr
>
(
lease
,
remove_lease
,
boost
::
bind
(
&
LeaseMgr
::
updateLease4
,
&
lease_mgr
,
_1
));
}
// Reclaim the lease - depending on the configuration, set the
// expired-reclaimed state or simply remove it.
reclaimLeaseInDatabase
<
Lease4Ptr
>
(
lease
,
remove_lease
,
boost
::
bind
(
&
LeaseMgr
::
updateLease4
,
&
lease_mgr
,
_1
));
++
leases_processed
;
// Update statistics.
...
...
@@ -1430,6 +1496,16 @@ AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeo
.
arg
(
lease
->
addr_
.
toText
())
.
arg
(
ex
.
what
());
}
// Check if we have hit the timeout for running reclamation routine and
// return if we have. We're checking it here, because we always want to
// allow reclaiming at least one lease.
if
((
timeout
>
0
)
&&
(
stopwatch
.
getTotalMilliseconds
()
>=
timeout
))
{
LOG_DEBUG
(
alloc_engine_logger
,
ALLOC_ENGINE_DBG_TRACE
,
ALLOC_ENGINE_V6_LEASES_RECLAMATION_TIMEOUT
)
.
arg
(
timeout
);
break
;
}
}
// Stop measuring the time.
...
...
@@ -1438,7 +1514,7 @@ AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeo
// Mark completion of the lease reclamation routine and present some stats.
LOG_DEBUG
(
alloc_engine_logger
,
ALLOC_ENGINE_DBG_TRACE
,
ALLOC_ENGINE_V4_LEASES_RECLAMATION_COMPLETE
)
.
arg
(
leases
.
size
()
)
.
arg
(
leases
_processed
)
.
arg
(
stopwatch
.
logFormatTotalDuration
());
}
...
...
src/lib/dhcpsrv/alloc_engine.h
View file @
e50fd180
...
...
@@ -480,7 +480,7 @@ public:
/// else (see host reservation)
/// - client's leases does not match his reservations
///
/// This method will call
the lease6_renew callout.
/// This method will call the lease6_renew callout.
///
/// @param ctx Message processing context. It holds various information
/// extracted from the client's message and required to allocate a lease.
...
...
@@ -507,7 +507,7 @@ public:
///
/// @param max_leases Maximum number of leases to be reclaimed.
/// @param timeout Maximum amount of time that the reclaimation routine
/// may be processing expired leases, expressed in seconds.
/// may be processing expired leases, expressed in
milli
seconds.
/// @param remove_lease A boolean value indicating if the lease should
/// be removed when it is reclaimed (if true) or it should be left in the
/// database in the "expired-reclaimed" state (if false).
...
...
@@ -522,7 +522,7 @@ public:
///
/// This method is executed periodically to act upon expired leases. This
/// includes for each lease:
/// - executing "lease_expire
6
" hook,
/// - executing "lease_expire
4
" hook,
/// - removing DNS record for a lease,
/// - reclaiming a lease in the database, i.e. setting its state to
/// "expired-reclaimed" or removing it from the lease databse,
...
...
@@ -530,7 +530,7 @@ public:
///
/// @param max_leases Maximum number of leases to be reclaimed.
/// @param timeout Maximum amount of time that the reclaimation routine
/// may be processing expired leases, expressed in seconds.
/// may be processing expired leases, expressed in
milli
seconds.
/// @param remove_lease A boolean value indicating if the lease should
/// be removed when it is reclaimed (if true) or it should be left in the
/// database in the "expired-reclaimed" state (if false).
...
...
src/lib/dhcpsrv/alloc_engine_messages.mes
View file @
e50fd180
...
...
@@ -82,6 +82,14 @@ reclamation of the expired leases. The maximum number of leases to
be reclaimed and the timeout is included in the message. If any of
these values is 0, it means "unlimited".
% ALLOC_ENGINE_V4_LEASES_RECLAMATION_TIMEOUT timeout of %1 ms reached while reclaiming IPv4 leases
This debug message is issued when the allocation engine hits the
timeout for performing reclamation of the expired leases. The
reclamation will now be interrupted and all leases which haven't
been reclaimed, because of the timeout, will be reclaimed when the
next scheduled reclamation is started. The argument is the timeout
value expressed in milliseconds.
% ALLOC_ENGINE_V4_OFFER_EXISTING_LEASE allocation engine will try to offer existing lease to the client %1
This message is issued when the allocation engine determines that
the client has a lease in the lease database, it doesn't have
...
...
@@ -300,6 +308,14 @@ reclamation of the expired leases. The maximum number of leases to
be reclaimed and the timeout is included in the message. If any of
these values is 0, it means "unlimited".
% ALLOC_ENGINE_V6_LEASES_RECLAMATION_TIMEOUT timeout of %1 ms reached while reclaiming IPv6 leases
This debug message is issued when the allocation engine hits the
timeout for performing reclamation of the expired leases. The
reclamation will now be interrupted and all leases which haven't
been reclaimed, because of the timeout, will be reclaimed when the
next scheduled reclamation is started. The argument is the timeout
value expressed in milliseconds.
% ALLOC_ENGINE_V6_RENEW_HR allocating leases reserved for the client %1 as a result of Renew
This debug message is issued when the allocation engine tries to
allocate reserved leases for the client sending a Renew message.
...
...
src/lib/dhcpsrv/tests/alloc_engine_expiration_unittest.cc
View file @
e50fd180
...
...
@@ -18,6 +18,7 @@
#include
<dhcp_ddns/ncr_msg.h>
#include
<dhcpsrv/tests/alloc_engine_utils.h>
#include
<dhcpsrv/tests/test_utils.h>
#include
<hooks/hooks_manager.h>
#include
<stats/stats_mgr.h>
#include
<gtest/gtest.h>
#include
<boost/bind.hpp>
...
...
@@ -26,6 +27,7 @@
#include
<iomanip>
#include
<sstream>
#include
<time.h>
#include
<unistd.h>
#include
<vector>
using
namespace
std
;
...
...
@@ -34,6 +36,7 @@ using namespace isc::asiolink;
using
namespace
isc
::
dhcp
;
using
namespace
isc
::
dhcp
::
test
;
using
namespace
isc
::
dhcp_ddns
;
using
namespace
isc
::
hooks
;
using
namespace
isc
::
stats
;
namespace
{
...
...
@@ -88,6 +91,12 @@ struct UpperBound {
size_t
upper_bound_
;
};
/// @brief List holding addresses for executed callouts.
std
::
list
<
IOAddress
>
callouts_
;
/// @brief Callout argument name for expired lease.
std
::
string
callout_argument_name
(
"lease4"
);
/// @brief Base test fixture class for the lease reclamation routines in the
/// @c AllocEngine.
///
...
...
@@ -150,11 +159,6 @@ struct UpperBound {
/// See @c ExpirationAllocEngineTest::testLeases for further details.
///
/// @todo These tests should be extended to cover the following cases:
/// - timeout value in the lease reclamation routines - the most reliable
/// way to test it will be by attaching a lease4_expire/lease6_expire
/// hooks which would block for a specific period of time. This will
/// allow for calculating the approximate number of reclaimed leases
/// within a given timeout. See ticket #3972.
/// - declined leases - declined leases expire and should be removed
/// from the lease database by the lease reclamation routine. See
/// ticket #3976.
...
...
@@ -211,6 +215,9 @@ public:
// Kill lease manager.
LeaseMgrFactory
::
destroy
();
// Remove callouts executed.
callouts_
.
clear
();
}
/// @brief Starts D2 client.
...
...
@@ -452,6 +459,75 @@ public:
return
(
true
);
}
/// @brief Lease algorithm checking if callout has been executed for
/// the expired lease.
///
/// @param lease Pointer to lease.
/// @return true if callout has been executed for the lease.
static
bool
leaseCalloutExecuted
(
const
LeasePtrType
&
lease
)
{
return
(
std
::
find
(
callouts_
.
begin
(),
callouts_
.
end
(),
lease
->
addr_
)
!=
callouts_
.
end
());
}
/// @brief Lease algorithm checking if callout hasn't been executed for
/// the expired lease.
///
/// @param lease Pointer to lease.
/// @return true if callout hasn't been executed for the lease.
static
bool
leaseCalloutNotExecuted
(
const
LeasePtrType
&
lease
)
{
return
(
!
leaseCalloutExecuted
(
lease
));
}
/// @brief Implements "lease{4,6}_expire" callout.
///
/// @param callout_handle Callout handle.
/// @return Zero.
static
int
leaseExpireCallout
(
CalloutHandle
&
callout_handle
)
{
LeasePtrType
lease
;
callout_handle
.
getArgument
(
callout_argument_name
,
lease
);
bool
remove_lease
=
true
;
callout_handle
.
getArgument
(
"remove_lease"
,
remove_lease
);
// Check if the remove_lease is set to false and assume that the callout
// has been successfully executed if it is. This is mainly to test
// that the lease reclamation routine sets this value at all.
if
(
!
remove_lease
)
{
callouts_
.
push_back
(
lease
->
addr_
);
}
return
(
0
);
}
/// @brief Implements "lease{4,6}_expire callout returning skip flag.
///
/// @param callout_handle Callout handle.
/// @return Zero.
static
int
leaseExpireWithSkipCallout
(
CalloutHandle
&
callout_handle
)
{
leaseExpireCallout
(
callout_handle
);
callout_handle
.
setSkip
(
true
);
return
(
0
);
}
/// @brief Implements "lease{4,6}_expire callout, which lasts at least
/// 2ms.
///
/// This callout is useful to test scenarios where the reclamation of the
/// lease needs to take a known amount of time. If the callout is installed
/// it will take at least 2ms for each lease. It is then possible to calculate
/// the approximate time that the reclamation of all leases would take and
/// test that the timeouts for the leases' reclamation work as expected.
///
/// @param callout_handle Callout handle.
/// @return Zero.
static
int
leaseExpireWithDelayCallout
(
CalloutHandle
&
callout_handle
)
{
leaseExpireCallout
(
callout_handle
);
// Delay the return from the callout by 2ms.
usleep
(
2000
);
return
(
0
);
}
/// @brief Returns removal name change request from the D2 client queue.
///
/// @param lease Pointer to the lease to be matched with NCR.
...
...
@@ -734,12 +810,113 @@ public:
EXPECT_TRUE
(
testLeases
(
&
dnsUpdateGeneratedForLease
,
&
oddLeaseIndex
));
}
/// @brief This test verfies that callouts are executed for each expired
/// lease when installed.
void
testReclaimExpiredLeasesHooks
()
{
for
(
int
i
=
0
;
i
<
TEST_LEASES_NUM
;
++
i
)
{
if
(
evenLeaseIndex
(
i
))
{
expire
(
i
,
1000
-
i
);
}
}
vector
<
string
>
libraries
;
// no libraries at this time
HooksManager
::
loadLibraries
(
libraries
);
// Install a callout: lease4_expire or lease6_expire.
std
::
ostringstream
callout_name
;
callout_name
<<
callout_argument_name
<<
"_expire"
;
EXPECT_NO_THROW
(
HooksManager
::
preCalloutsLibraryHandle
().
registerCallout
(
callout_name
.
str
(),
leaseExpireCallout
));
ASSERT_NO_THROW
(
reclaimExpiredLeases
(
0
,
0
,
false
));
// Callouts should be executed for leases with even indexes and these
// leases should be reclaimed.
EXPECT_TRUE
(
testLeases
(
&
leaseCalloutExecuted
,
&
evenLeaseIndex
));
EXPECT_TRUE
(
testLeases
(
&
leaseReclaimed
,
&
evenLeaseIndex
));
// Callouts should not be executed for leases with odd indexes and these
// leases should not be reclaimed.
EXPECT_TRUE
(
testLeases
(
&
leaseCalloutNotExecuted
,
&
oddLeaseIndex
));
EXPECT_TRUE
(
testLeases
(
&
leaseNotReclaimed
,
&
oddLeaseIndex
));
}
/// @brief This test verfies that callouts are executed for each expired
/// lease and that the lease is not reclaimed when skip flag is set.
void
testReclaimExpiredLeasesHooksWithSkip
()
{
for
(
int
i
=
0
;
i
<
TEST_LEASES_NUM
;
++
i
)
{
if
(
evenLeaseIndex
(
i
))
{
expire
(
i
,
1000
-
i
);
}
}
vector
<
string
>
libraries
;
// no libraries at this time
HooksManager
::
loadLibraries
(
libraries
);
// Install a callout: lease4_expire or lease6_expire.
std
::
ostringstream
callout_name
;
callout_name
<<
callout_argument_name
<<
"_expire"
;
EXPECT_NO_THROW
(
HooksManager
::
preCalloutsLibraryHandle
().
registerCallout
(
callout_name
.
str
(),
leaseExpireWithSkipCallout
));
ASSERT_NO_THROW
(
reclaimExpiredLeases
(
0
,
0
,
false
));
// Callouts should have been executed for leases with even indexes.
EXPECT_TRUE
(
testLeases
(
&
leaseCalloutExecuted
,
&
evenLeaseIndex
));
// Callouts should not be executed for leases with odd indexes.
EXPECT_TRUE
(
testLeases
(
&
leaseCalloutNotExecuted
,
&
oddLeaseIndex
));
// Leases shouldn't be reclaimed because the callout sets the
// skip flag for each of them.
EXPECT_TRUE
(
testLeases
(
&
leaseNotReclaimed
,
&
allLeaseIndexes
));
}
/// @brief This test verifies that it is possible to set the timeout for
/// the execution of the lease reclamation routine.
void
testReclaimExpiredLeasesTimeout
(
const
uint16_t
timeout
)
{
// Leases are segregated from the most expired to the least expired.
for
(
int
i
=
0
;
i
<
TEST_LEASES_NUM
;
++
i
)
{
expire
(
i
,
2000
-
i
);
}
vector
<
string
>
libraries
;
HooksManager
::
loadLibraries
(
libraries
);
// Install a callout: lease4_expire or lease6_expire. Each callout
// takes at least 2ms to run (it uses usleep).
std
::
ostringstream
callout_name
;
callout_name
<<
callout_argument_name
<<
"_expire"
;
EXPECT_NO_THROW
(
HooksManager
::
preCalloutsLibraryHandle
().
registerCallout
(
callout_name
.
str
(),
leaseExpireWithDelayCallout
));
// Reclaim leases with timeout.
ASSERT_NO_THROW
(
reclaimExpiredLeases
(
0
,
timeout
,
false
));
// We reclaimed at most (timeout / 2ms) leases.
const
uint16_t
theoretical_reclaimed
=
static_cast
<
uint16_t
>
(
timeout
/
2
);
// The actual number of leases reclaimed is likely to be lower than
// the theoretical number. For low theoretical number the adjusted
// number is always 1. For higher number, it will be 10 less than the
// theoretical number.
const
uint16_t
adjusted_reclaimed
=
(
theoretical_reclaimed
>
10
?
theoretical_reclaimed
-
10
:
1
);
EXPECT_TRUE
(
testLeases
(
&
leaseCalloutExecuted
,
&
allLeaseIndexes
,
LowerBound
(
0
),
UpperBound
(
adjusted_reclaimed
)));
EXPECT_TRUE
(
testLeases
(
&
leaseReclaimed
,
&
allLeaseIndexes
,
LowerBound
(
0
),
UpperBound
(
adjusted_reclaimed
)));
EXPECT_TRUE
(
testLeases
(
&
leaseCalloutNotExecuted
,
&
allLeaseIndexes
,
LowerBound
(
theoretical_reclaimed
+
1
),
UpperBound
(
TEST_LEASES_NUM
)));
EXPECT_TRUE
(
testLeases
(
&
leaseNotReclaimed
,
&
allLeaseIndexes
,
LowerBound
(
theoretical_reclaimed
+
1
),
UpperBound
(
TEST_LEASES_NUM
)));
}
/// @brief Collection of leases created at construction time.
std
::
vector
<
LeasePtrType
>
leases_
;
/// @brief Allocation engine instance used for tests.
AllocEnginePtr
engine_
;
};