summaryrefslogtreecommitdiffstats
path: root/src/bin
diff options
context:
space:
mode:
authorRazvan Becheriu <razvan@isc.org>2022-10-10 17:19:18 +0200
committerRazvan Becheriu <razvan@isc.org>2022-10-25 09:05:53 +0200
commita131e8ea3ffa25be85b36f1cc9df7a0723b916ce (patch)
tree2c98620437c25928512d30f38c96d09424b895dc /src/bin
parent[#2607] bump lib versions for 2.3.2 (diff)
downloadkea-a131e8ea3ffa25be85b36f1cc9df7a0723b916ce.tar.xz
kea-a131e8ea3ffa25be85b36f1cc9df7a0723b916ce.zip
[#2548] expire lease on release if affinity is enabled
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/dhcp4/dhcp4_messages.cc4
-rw-r--r--src/bin/dhcp4/dhcp4_messages.h2
-rw-r--r--src/bin/dhcp4/dhcp4_messages.mes12
-rw-r--r--src/bin/dhcp4/dhcp4_srv.cc41
-rw-r--r--src/bin/dhcp4/tests/dhcp4_test_utils.cc14
-rw-r--r--src/bin/dhcp4/tests/dhcp4_test_utils.h10
-rw-r--r--src/bin/dhcp4/tests/fqdn_unittest.cc45
-rw-r--r--src/bin/dhcp4/tests/hooks_unittest.cc1204
-rw-r--r--src/bin/dhcp4/tests/out_of_range_unittest.cc290
-rw-r--r--src/bin/dhcp4/tests/release_unittest.cc151
-rw-r--r--src/bin/dhcp4/tests/shared_network_unittest.cc2
-rw-r--r--src/bin/dhcp6/dhcp6_messages.cc8
-rw-r--r--src/bin/dhcp6/dhcp6_messages.h4
-rw-r--r--src/bin/dhcp6/dhcp6_messages.mes31
-rw-r--r--src/bin/dhcp6/dhcp6_srv.cc98
-rw-r--r--src/bin/dhcp6/tests/dhcp6_srv_unittest.cc36
-rw-r--r--src/bin/dhcp6/tests/dhcp6_test_utils.cc66
-rw-r--r--src/bin/dhcp6/tests/dhcp6_test_utils.h38
-rw-r--r--src/bin/dhcp6/tests/fqdn_unittest.cc47
-rw-r--r--src/bin/dhcp6/tests/hooks_unittest.cc2707
20 files changed, 2875 insertions, 1935 deletions
diff --git a/src/bin/dhcp4/dhcp4_messages.cc b/src/bin/dhcp4/dhcp4_messages.cc
index e93a9b0022..7f2ebf6a9a 100644
--- a/src/bin/dhcp4/dhcp4_messages.cc
+++ b/src/bin/dhcp4/dhcp4_messages.cc
@@ -140,7 +140,9 @@ extern const isc::log::MessageID DHCP4_POST_ALLOCATION_NAME_UPDATE_FAIL = "DHCP4
extern const isc::log::MessageID DHCP4_QUERY_DATA = "DHCP4_QUERY_DATA";
extern const isc::log::MessageID DHCP4_RECLAIM_EXPIRED_LEASES_FAIL = "DHCP4_RECLAIM_EXPIRED_LEASES_FAIL";
extern const isc::log::MessageID DHCP4_RELEASE = "DHCP4_RELEASE";
+extern const isc::log::MessageID DHCP4_RELEASE_DELETED = "DHCP4_RELEASE_DELETED";
extern const isc::log::MessageID DHCP4_RELEASE_EXCEPTION = "DHCP4_RELEASE_EXCEPTION";
+extern const isc::log::MessageID DHCP4_RELEASE_EXPIRED = "DHCP4_RELEASE_EXPIRED";
extern const isc::log::MessageID DHCP4_RELEASE_FAIL = "DHCP4_RELEASE_FAIL";
extern const isc::log::MessageID DHCP4_RELEASE_FAIL_NO_LEASE = "DHCP4_RELEASE_FAIL_NO_LEASE";
extern const isc::log::MessageID DHCP4_RELEASE_FAIL_WRONG_CLIENT = "DHCP4_RELEASE_FAIL_WRONG_CLIENT";
@@ -307,7 +309,9 @@ const char* values[] = {
"DHCP4_QUERY_DATA", "%1, packet details: %2",
"DHCP4_RECLAIM_EXPIRED_LEASES_FAIL", "failed to reclaim expired leases: %1",
"DHCP4_RELEASE", "%1: address %2 was released properly.",
+ "DHCP4_RELEASE_DELETED", "%1: address %2 was properly deleted on release.",
"DHCP4_RELEASE_EXCEPTION", "%1: while trying to release address %2 an exception occurred: %3",
+ "DHCP4_RELEASE_EXPIRED", "%1: address %2 was properly expired on release.",
"DHCP4_RELEASE_FAIL", "%1: failed to remove lease for address %2",
"DHCP4_RELEASE_FAIL_NO_LEASE", "%1: client is trying to release non-existing lease %2",
"DHCP4_RELEASE_FAIL_WRONG_CLIENT", "%1: client is trying to release the lease %2 which belongs to a different client",
diff --git a/src/bin/dhcp4/dhcp4_messages.h b/src/bin/dhcp4/dhcp4_messages.h
index 1ff14ac5e0..b5ead0792d 100644
--- a/src/bin/dhcp4/dhcp4_messages.h
+++ b/src/bin/dhcp4/dhcp4_messages.h
@@ -141,7 +141,9 @@ extern const isc::log::MessageID DHCP4_POST_ALLOCATION_NAME_UPDATE_FAIL;
extern const isc::log::MessageID DHCP4_QUERY_DATA;
extern const isc::log::MessageID DHCP4_RECLAIM_EXPIRED_LEASES_FAIL;
extern const isc::log::MessageID DHCP4_RELEASE;
+extern const isc::log::MessageID DHCP4_RELEASE_DELETED;
extern const isc::log::MessageID DHCP4_RELEASE_EXCEPTION;
+extern const isc::log::MessageID DHCP4_RELEASE_EXPIRED;
extern const isc::log::MessageID DHCP4_RELEASE_FAIL;
extern const isc::log::MessageID DHCP4_RELEASE_FAIL_NO_LEASE;
extern const isc::log::MessageID DHCP4_RELEASE_FAIL_WRONG_CLIENT;
diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes
index a5afe6e568..742d4fcd23 100644
--- a/src/bin/dhcp4/dhcp4_messages.mes
+++ b/src/bin/dhcp4/dhcp4_messages.mes
@@ -791,6 +791,18 @@ is a normal operation during client shutdown. The first argument includes
the client and transaction identification information. The second argument
includes the released IPv4 address.
+% DHCP4_RELEASE_EXPIRED %1: address %2 was properly expired on release.
+This informational message indicates that an address was properly expired on
+release. It is a normal operation during client shutdown. The first argument
+includes the client and transaction identification information. The second
+argument includes the released IPv4 address.
+
+% DHCP4_RELEASE_DELETED %1: address %2 was properly deleted on release.
+This informational message indicates that an address was properly deleted on
+release. It is a normal operation during client shutdown. The first argument
+includes the client and transaction identification information. The second
+argument includes the released IPv4 address.
+
% DHCP4_RELEASE_EXCEPTION %1: while trying to release address %2 an exception occurred: %3
This message is output when an error was encountered during an attempt
to process a DHCPRELEASE message. The error will not affect the client,
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index df0b100047..bb29c8fe49 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -3427,12 +3427,26 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release, AllocEngine::ClientContext4Ptr& cont
}
// Callout didn't indicate to skip the release process. Let's release
- // the lease.
+ // the address.
if (!skip) {
- bool success = LeaseMgrFactory::instance().deleteLease(lease);
+ // Ok, we've passed all checks. Let's release this address.
+ bool success = false; // was the removal operation successful?
+ bool expired = false; // explicitly expired instead of removed?
+ auto expiration_cfg = CfgMgr::instance().getCurrentCfg()->getCfgExpiration();
+
+ // Delete lease only if affinity is disabled.
+ if (expiration_cfg->getFlushReclaimedTimerWaitTime() &&
+ expiration_cfg->getHoldReclaimedTime()) {
+ // Expire the lease.
+ lease->cltt_ -= lease->valid_lft_ + 1;
+ LeaseMgrFactory::instance().updateLease4(lease);
+ expired = true;
+ success = true;
+ } else {
+ success = LeaseMgrFactory::instance().deleteLease(lease);
+ }
if (success) {
-
context.reset(new AllocEngine::ClientContext4());
context->old_lease_ = lease;
@@ -3441,14 +3455,23 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release, AllocEngine::ClientContext4Ptr& cont
.arg(release->getLabel())
.arg(lease->addr_.toText());
- // Need to decrease statistic for assigned addresses.
- StatsMgr::instance().addValue(
- StatsMgr::generateName("subnet", lease->subnet_id_, "assigned-addresses"),
- static_cast<int64_t>(-1));
+ if (expired) {
+ LOG_INFO(lease4_logger, DHCP4_RELEASE_EXPIRED)
+ .arg(release->getLabel())
+ .arg(lease->addr_.toText());
+ } else {
+ LOG_INFO(lease4_logger, DHCP4_RELEASE_DELETED)
+ .arg(release->getLabel())
+ .arg(lease->addr_.toText());
- // Remove existing DNS entries for the lease, if any.
- queueNCR(CHG_REMOVE, lease);
+ // Need to decrease statistic for assigned addresses.
+ StatsMgr::instance().addValue(
+ StatsMgr::generateName("subnet", lease->subnet_id_, "assigned-addresses"),
+ static_cast<int64_t>(-1));
+ // Remove existing DNS entries for the lease, if any.
+ queueNCR(CHG_REMOVE, lease);
+ }
} else {
// Release failed
LOG_ERROR(lease4_logger, DHCP4_RELEASE_FAIL)
diff --git a/src/bin/dhcp4/tests/dhcp4_test_utils.cc b/src/bin/dhcp4/tests/dhcp4_test_utils.cc
index 6916da5e78..91f9d42521 100644
--- a/src/bin/dhcp4/tests/dhcp4_test_utils.cc
+++ b/src/bin/dhcp4/tests/dhcp4_test_utils.cc
@@ -802,8 +802,9 @@ Dhcpv4SrvTest::configure(const std::string& config,
const bool commit,
const bool open_sockets,
const bool create_managers,
- const bool test) {
- configure(config, srv_, commit, open_sockets, create_managers, test);
+ const bool test,
+ const bool disable_affinity) {
+ configure(config, srv_, commit, open_sockets, create_managers, test, disable_affinity);
}
void
@@ -812,7 +813,8 @@ Dhcpv4SrvTest::configure(const std::string& config,
const bool commit,
const bool open_sockets,
const bool create_managers,
- const bool test) {
+ const bool test,
+ const bool disable_affinity) {
setenv("KEA_LFC_EXECUTABLE", KEA_LFC_EXECUTABLE, 1);
MultiThreadingCriticalSection cs;
ConstElementPtr json;
@@ -850,6 +852,12 @@ Dhcpv4SrvTest::configure(const std::string& config,
} );
}
+ if (disable_affinity) {
+ auto expiration_cfg = CfgMgr::instance().getStagingCfg()->getCfgExpiration();
+ expiration_cfg->setFlushReclaimedTimerWaitTime(0);
+ expiration_cfg->setHoldReclaimedTime(0);
+ }
+
try {
CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
} catch (const std::exception& ex) {
diff --git a/src/bin/dhcp4/tests/dhcp4_test_utils.h b/src/bin/dhcp4/tests/dhcp4_test_utils.h
index 17a3d5a75d..5436a67f9e 100644
--- a/src/bin/dhcp4/tests/dhcp4_test_utils.h
+++ b/src/bin/dhcp4/tests/dhcp4_test_utils.h
@@ -559,11 +559,14 @@ public:
/// @param create_managers A boolean flag indicating if managers should be
/// recreated.
/// @param test A boolean flag which indicates if only testing config.
+ /// @param disable_affinity A boolean flag which indicates if lease affinity
+ /// should be disabled.
void configure(const std::string& config,
const bool commit = true,
const bool open_sockets = true,
const bool create_managers = true,
- const bool test = false);
+ const bool test = false,
+ const bool disable_affinity = true);
/// @brief Configure specified DHCP server using JSON string.
///
@@ -576,12 +579,15 @@ public:
/// @param create_managers A boolean flag indicating if managers should be
/// recreated.
/// @param test A boolean flag which indicates if only testing config.
+ /// @param disable_affinity A boolean flag which indicates if lease affinity
+ /// should be disabled.
void configure(const std::string& config,
NakedDhcpv4Srv& srv,
const bool commit = true,
const bool open_sockets = true,
const bool create_managers = true,
- const bool test = false);
+ const bool test = false,
+ const bool disable_affinity = true);
/// @brief Configure specified DHCP server using JSON string.
///
diff --git a/src/bin/dhcp4/tests/fqdn_unittest.cc b/src/bin/dhcp4/tests/fqdn_unittest.cc
index 2a275c6041..2e3ce3e24a 100644
--- a/src/bin/dhcp4/tests/fqdn_unittest.cc
+++ b/src/bin/dhcp4/tests/fqdn_unittest.cc
@@ -1520,11 +1520,14 @@ TEST_F(NameDhcpv4SrvTest, processRequestRenewHostname) {
// Test that when a release message is sent for a previously acquired lease,
// DDNS updates are enabled that the server generates a NameChangeRequest
-// to remove entries corresponding to the released lease.
+// to remove entries corresponding to the released (deleted) lease.
TEST_F(NameDhcpv4SrvTest, processRequestRelease) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setFlushReclaimedTimerWaitTime(0);
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setHoldReclaimedTime(0);
+
// Verify the updates are enabled.
ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
@@ -1563,6 +1566,46 @@ TEST_F(NameDhcpv4SrvTest, processRequestRelease) {
time(NULL), subnet_->getValid(), true);
}
+// Test that when a release message is sent for a previously acquired lease,
+// DDNS updates are enabled that the server does not generate a NameChangeRequest
+// to remove entries corresponding to the released (expired) lease.
+TEST_F(NameDhcpv4SrvTest, processRequestReleaseNoDelete) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ // Verify the updates are enabled.
+ ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
+
+ // Create and process a lease request so we have a lease to release.
+ Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
+ Option4ClientFqdn::FLAG_E,
+ "myhost.example.com.",
+ Option4ClientFqdn::FULL, true);
+ Pkt4Ptr reply;
+ ASSERT_NO_THROW(reply = srv_->processRequest(req));
+ checkResponse(reply, DHCPACK, 1234);
+
+ // Verify that there is one NameChangeRequest generated for lease.
+ ASSERT_EQ(1, d2_mgr_.getQueueSize());
+ verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
+ reply->getYiaddr().toText(), "myhost.example.com.",
+ "00010132E91AA355CFBB753C0F0497A5A940436"
+ "965B68B6D438D98E680BF10B09F3BCF",
+ time(NULL), subnet_->getValid(), true);
+
+ // Create and process the Release message.
+ Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
+ rel->setCiaddr(reply->getYiaddr());
+ rel->setRemoteAddr(IOAddress("192.0.2.3"));
+ rel->addOption(generateClientId());
+ rel->addOption(srv_->getServerID());
+ ASSERT_NO_THROW(srv_->processRelease(rel));
+
+ // The lease has been expired, so there should not be a NameChangeRequest to
+ // remove corresponding DNS entries.
+ ASSERT_EQ(0, d2_mgr_.getQueueSize());
+}
+
// Test that when the Release message is sent for a previously acquired lease
// and DDNS updates are disabled that server does NOT generate a
// NameChangeRequest to remove entries corresponding to the released lease.
diff --git a/src/bin/dhcp4/tests/hooks_unittest.cc b/src/bin/dhcp4/tests/hooks_unittest.cc
index 84d37f8d97..4c092e6716 100644
--- a/src/bin/dhcp4/tests/hooks_unittest.cc
+++ b/src/bin/dhcp4/tests/hooks_unittest.cc
@@ -6,76 +6,94 @@
#include <config.h>
-#include <dhcp4/tests/dhcp4_test_utils.h>
-#include <dhcp4/ctrl_dhcp4_srv.h>
-#include <dhcp4/json_config_parser.h>
+#include <asiolink/io_address.h>
#include <asiolink/io_service.h>
#include <cc/command_interpreter.h>
#include <config/command_mgr.h>
-#include <hooks/server_hooks.h>
-#include <hooks/hooks_manager.h>
-#include <hooks/callout_manager.h>
-#include <dhcpsrv/cfgmgr.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcp/option.h>
-#include <asiolink/io_address.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
+#include <dhcp4/json_config_parser.h>
#include <dhcp4/tests/dhcp4_client.h>
+#include <dhcp4/tests/dhcp4_test_utils.h>
#include <dhcp4/tests/marker_file.h>
#include <dhcp4/tests/test_libraries.h>
+#include <hooks/server_hooks.h>
+#include <hooks/hooks_manager.h>
+#include <hooks/callout_manager.h>
#include <stats/stats_mgr.h>
#include <util/multi_threading_mgr.h>
#include <vector>
-using namespace std;
+
using namespace isc::asiolink;
-using namespace isc::data;
-using namespace isc::hooks;
using namespace isc::config;
-using namespace isc::dhcp::test;
+using namespace isc::data;
using namespace isc::dhcp;
-using namespace isc::util;
+using namespace isc::dhcp::test;
+using namespace isc::hooks;
using namespace isc::stats;
+using namespace isc::util;
+
+using namespace std;
-// Checks if hooks are registered properly.
+// namespace has to be named, because friends are defined in Dhcpv6Srv class
+// Maybe it should be isc::test?
+namespace {
+
+// Checks if hooks are implemented properly.
TEST_F(Dhcpv4SrvTest, Hooks) {
NakedDhcpv4Srv srv(0);
// check if appropriate hooks are registered
- int hook_index_buffer4_receive = -1;
- int hook_index_pkt4_receive = -1;
- int hook_index_select_subnet = -1;
+ int hook_index_dhcp4_srv_configured = -1;
+ int hook_index_buffer4_receive = -1;
+ int hook_index_buffer4_send = -1;
+ int hook_index_lease4_renew = -1;
+ int hook_index_lease4_release = -1;
+ int hook_index_lease4_decline = -1;
+ int hook_index_pkt4_receive = -1;
+ int hook_index_pkt4_send = -1;
+ int hook_index_select_subnet = -1;
int hook_index_leases4_committed = -1;
- int hook_index_lease4_release = -1;
- int hook_index_pkt4_send = -1;
- int hook_index_buffer4_send = -1;
- int hook_index_host4_identifier = -1;
+ int hook_index_host4_identifier = -1;
// check if appropriate indexes are set
+ EXPECT_NO_THROW(hook_index_dhcp4_srv_configured = ServerHooks::getServerHooks()
+ .getIndex("dhcp4_srv_configured"));
EXPECT_NO_THROW(hook_index_buffer4_receive = ServerHooks::getServerHooks()
.getIndex("buffer4_receive"));
+ EXPECT_NO_THROW(hook_index_buffer4_send = ServerHooks::getServerHooks()
+ .getIndex("buffer4_send"));
+ EXPECT_NO_THROW(hook_index_lease4_renew = ServerHooks::getServerHooks()
+ .getIndex("lease4_renew"));
+ EXPECT_NO_THROW(hook_index_lease4_release = ServerHooks::getServerHooks()
+ .getIndex("lease4_release"));
+ EXPECT_NO_THROW(hook_index_lease4_decline = ServerHooks::getServerHooks()
+ .getIndex("lease4_decline"));
EXPECT_NO_THROW(hook_index_pkt4_receive = ServerHooks::getServerHooks()
.getIndex("pkt4_receive"));
+ EXPECT_NO_THROW(hook_index_pkt4_send = ServerHooks::getServerHooks()
+ .getIndex("pkt4_send"));
EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
.getIndex("subnet4_select"));
EXPECT_NO_THROW(hook_index_leases4_committed = ServerHooks::getServerHooks()
.getIndex("leases4_committed"));
- EXPECT_NO_THROW(hook_index_lease4_release = ServerHooks::getServerHooks()
- .getIndex("lease4_release"));
- EXPECT_NO_THROW(hook_index_pkt4_send = ServerHooks::getServerHooks()
- .getIndex("pkt4_send"));
- EXPECT_NO_THROW(hook_index_buffer4_send = ServerHooks::getServerHooks()
- .getIndex("buffer4_send"));
EXPECT_NO_THROW(hook_index_host4_identifier = ServerHooks::getServerHooks()
.getIndex("host4_identifier"));
+ EXPECT_TRUE(hook_index_dhcp4_srv_configured > 0);
EXPECT_TRUE(hook_index_buffer4_receive > 0);
+ EXPECT_TRUE(hook_index_buffer4_send > 0);
+ EXPECT_TRUE(hook_index_lease4_renew > 0);
+ EXPECT_TRUE(hook_index_lease4_release > 0);
+ EXPECT_TRUE(hook_index_lease4_decline > 0);
EXPECT_TRUE(hook_index_pkt4_receive > 0);
+ EXPECT_TRUE(hook_index_pkt4_send > 0);
EXPECT_TRUE(hook_index_select_subnet > 0);
EXPECT_TRUE(hook_index_leases4_committed > 0);
- EXPECT_TRUE(hook_index_lease4_release > 0);
- EXPECT_TRUE(hook_index_pkt4_send > 0);
- EXPECT_TRUE(hook_index_buffer4_send > 0);
EXPECT_TRUE(hook_index_host4_identifier > 0);
}
@@ -113,20 +131,23 @@ public:
}
// Allocate new DHCPv4 Server
- srv_ = new NakedDhcpv4Srv(0);
+ srv_.reset(new NakedDhcpv4Srv(0));
- // clear static buffers
+ // Clear static buffers
resetCalloutBuffers();
io_service_ = boost::make_shared<IOService>();
+ // Reset the hook system in its original state
+ HooksManager::unloadLibraries();
+
// Clear statistics.
StatsMgr::instance().removeAll();
}
/// @brief destructor (deletes Dhcpv4Srv)
virtual ~HooksDhcpv4SrvTest() {
- // clear static buffers
+ // Clear static buffers
resetCalloutBuffers();
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("dhcp4_srv_configured");
@@ -135,12 +156,12 @@ public:
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_receive");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_send");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("subnet4_select");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("leases4_committed");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_renew");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_release");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_decline");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("host4_identifier");
- delete srv_;
HooksManager::setTestMode(false);
bool status = HooksManager::unloadLibraries();
if (!status) {
@@ -161,7 +182,7 @@ public:
/// @return pointer to create option object
static OptionPtr createOption(uint16_t option_code) {
- char payload[] = {
+ uint8_t payload[] = {
0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
};
@@ -257,6 +278,7 @@ public:
if (callback_qry_pkt4_) {
callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
}
+
return (0);
}
@@ -280,31 +302,31 @@ public:
return buffer4_receive_callout(callout_handle);
}
- /// Test callback that sets drop flag
+ /// Test callback that sets skip flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- buffer4_receive_drop(CalloutHandle& callout_handle) {
+ buffer4_receive_skip(CalloutHandle& callout_handle) {
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
// Carry on as usual
return buffer4_receive_callout(callout_handle);
}
- /// Test callback that sets skip flag
+ /// Test callback that sets drop flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- buffer4_receive_skip(CalloutHandle& callout_handle) {
+ buffer4_receive_drop(CalloutHandle& callout_handle) {
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
// Carry on as usual
return buffer4_receive_callout(callout_handle);
}
- /// test callback that stores received callout name and pkt4 value
+ /// Test callback that stores received callout name and pkt4 value
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
@@ -322,7 +344,7 @@ public:
return (0);
}
- /// test callback that changes client-id value
+ /// Test callback that changes client-id value
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
@@ -331,17 +353,17 @@ public:
Pkt4Ptr pkt;
callout_handle.getArgument("query4", pkt);
- // get rid of the old client-id
+ // Get rid of the old client-id
pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
- // add a new option
+ // Add a new option
pkt->addOption(createOption(DHO_DHCP_CLIENT_IDENTIFIER));
- // carry on as usual
+ // Carry on as usual
return pkt4_receive_callout(callout_handle);
}
- /// test callback that deletes client-id
+ /// Test callback that deletes client-id
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
@@ -350,42 +372,42 @@ public:
Pkt4Ptr pkt;
callout_handle.getArgument("query4", pkt);
- // get rid of the old client-id (and no HWADDR)
+ // Get rid of the old client-id (and no HWADDR)
vector<uint8_t> mac;
pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
pkt->setHWAddr(1, 0, mac); // HWtype 1, hardware len = 0
- // carry on as usual
+ // Carry on as usual
return pkt4_receive_callout(callout_handle);
}
- /// test callback that sets drop flag
+ /// Test callback that sets skip flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- pkt4_receive_drop(CalloutHandle& callout_handle) {
+ pkt4_receive_skip(CalloutHandle& callout_handle) {
Pkt4Ptr pkt;
callout_handle.getArgument("query4", pkt);
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- // carry on as usual
+ // Carry on as usual
return pkt4_receive_callout(callout_handle);
}
- /// test callback that sets skip flag
+ /// Test callback that sets drop flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- pkt4_receive_skip(CalloutHandle& callout_handle) {
+ pkt4_receive_drop(CalloutHandle& callout_handle) {
Pkt4Ptr pkt;
callout_handle.getArgument("query4", pkt);
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
- // carry on as usual
+ // Carry on as usual
return pkt4_receive_callout(callout_handle);
}
@@ -422,17 +444,17 @@ public:
Pkt4Ptr pkt;
callout_handle.getArgument("response4", pkt);
- // get rid of the old server-id
+ // Get rid of the old server-id
pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
- // add a new option
+ // Add a new option
pkt->addOption(createOption(DHO_DHCP_SERVER_IDENTIFIER));
- // carry on as usual
+ // Carry on as usual
return pkt4_send_callout(callout_handle);
}
- /// test callback that deletes server-id
+ /// Test callback that deletes server-id
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
@@ -441,10 +463,10 @@ public:
Pkt4Ptr pkt;
callout_handle.getArgument("response4", pkt);
- // get rid of the old client-id
+ // Get rid of the old client-id
pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
- // carry on as usual
+ // Carry on as usual
return pkt4_send_callout(callout_handle);
}
@@ -478,8 +500,8 @@ public:
return pkt4_send_callout(callout_handle);
}
- /// Test callback that stores received callout name and pkt4 value
- /// @param callout_handle handle passed by the hooks framework
+ /// Test callback that stores response packet.
+ /// @param callout_handle handle passed by the hooks framework.
/// @return always 0
static int
buffer4_send_callout(CalloutHandle& callout_handle) {
@@ -512,26 +534,28 @@ public:
return (0);
}
- /// Test callback that stores received callout name and pkt4 value
+ /// Test callback that sets skip flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- skip_callout(CalloutHandle& callout_handle) {
+ buffer4_send_skip(CalloutHandle& callout_handle) {
callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- return (0);
+ // Carry on as usual
+ return buffer4_send_callout(callout_handle);
}
- /// Test callback that stores received callout name and pkt4 value
+ /// Test callback that sets drop flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- drop_callout(CalloutHandle& callout_handle) {
+ buffer4_send_drop(CalloutHandle& callout_handle) {
callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
- return (0);
+ // carry on as usual
+ return buffer4_send_callout(callout_handle);
}
/// Test callback that stores received callout name and subnet4 values
@@ -558,7 +582,7 @@ public:
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- subnet4_select_different_subnet_callout(CalloutHandle& callout_handle) {
+ subnet4_select_different_subnet(CalloutHandle& callout_handle) {
// Call the basic callout to record all passed values
subnet4_select_callout(callout_handle);
@@ -577,9 +601,23 @@ public:
return (0);
}
+ /// Test callback that sets skip flag
+ /// @param callout_handle handle passed by the hooks framework
+ /// @return always 0
+ static int
+ subnet4_select_skip(CalloutHandle& callout_handle) {
+
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+
+ // Carry on as usual
+ return subnet4_select_callout(callout_handle);
+ }
+
/// Test callback that sets drop flag
+ /// @param callout_handle handle passed by the hooks framework
+ /// @return always 0
static int
- subnet4_select_drop_callout(CalloutHandle& callout_handle) {
+ subnet4_select_drop(CalloutHandle& callout_handle) {
callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
@@ -587,15 +625,18 @@ public:
return subnet4_select_callout(callout_handle);
}
- /// Test callback that stores received callout name passed parameters
+ /// Test callback that stores received callout name and subnet4 values
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- lease4_release_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("lease4_release");
+ lease4_renew_callout(CalloutHandle& callout_handle) {
+ callback_name_ = string("lease4_renew");
callout_handle.getArgument("query4", callback_qry_pkt4_);
+ callout_handle.getArgument("subnet4", callback_subnet4_);
callout_handle.getArgument("lease4", callback_lease4_);
+ callout_handle.getArgument("hwaddr", callback_hwaddr_);
+ callout_handle.getArgument("clientid", callback_clientid_);
callback_argument_names_ = callout_handle.getArgumentNames();
@@ -606,18 +647,27 @@ public:
return (0);
}
- /// Test callback that stores received callout name and subnet4 values
+ /// Test callback that sets the skip flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- lease4_renew_callout(CalloutHandle& callout_handle) {
+ lease4_renew_skip_callout(CalloutHandle& callout_handle) {
callback_name_ = string("lease4_renew");
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+
+ return (0);
+ }
+
+ /// Test callback that stores received callout name passed parameters
+ /// @param callout_handle handle passed by the hooks framework
+ /// @return always 0
+ static int
+ lease4_release_callout(CalloutHandle& callout_handle) {
+ callback_name_ = string("lease4_release");
+
callout_handle.getArgument("query4", callback_qry_pkt4_);
- callout_handle.getArgument("subnet4", callback_subnet4_);
callout_handle.getArgument("lease4", callback_lease4_);
- callout_handle.getArgument("hwaddr", callback_hwaddr_);
- callout_handle.getArgument("clientid", callback_clientid_);
callback_argument_names_ = callout_handle.getArgumentNames();
@@ -628,6 +678,30 @@ public:
return (0);
}
+ /// Test callback that sets the skip flag
+ /// @param callout_handle handle passed by the hooks framework
+ /// @return always 0
+ static int
+ lease4_release_skip(CalloutHandle& callout_handle) {
+ callback_name_ = string("lease4_release");
+
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+
+ return (0);
+ }
+
+ /// Test callback that sets the drop flag
+ /// @param callout_handle handle passed by the hooks framework
+ /// @return always 0
+ static int
+ lease4_release_drop(CalloutHandle& callout_handle) {
+ callback_name_ = string("lease4_release");
+
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
+
+ return (0);
+ }
+
/// Test lease4_decline callback that stores received parameters.
///
/// @param callout_handle handle passed by the hooks framework
@@ -650,7 +724,7 @@ public:
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- lease4_decline_skip_callout(CalloutHandle& callout_handle) {
+ lease4_decline_skip(CalloutHandle& callout_handle) {
callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
return (lease4_decline_callout(callout_handle));
@@ -661,7 +735,7 @@ public:
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- lease4_decline_drop_callout(CalloutHandle& callout_handle) {
+ lease4_decline_drop(CalloutHandle& callout_handle) {
callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
return (lease4_decline_callout(callout_handle));
@@ -671,6 +745,7 @@ public:
static int
leases4_committed_callout(CalloutHandle& callout_handle) {
callback_name_ = string("leases4_committed");
+
callout_handle.getArgument("query4", callback_qry_pkt4_);
Lease4CollectionPtr leases4;
@@ -736,7 +811,7 @@ public:
return (0);
}
- /// @brief Test host4_identifier callout by setting identifier to "foo"
+ /// @brief Test host4_identifier callback by setting identifier to "foo"
///
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
@@ -755,6 +830,7 @@ public:
std::vector<uint8_t> id_test;
handle.getArgument("id_value", id_test);
+ // Ok, now set the identifier.
std::vector<uint8_t> id = { 0x66, 0x6f, 0x6f }; // foo
handle.setArgument("id_value", id);
handle.setArgument("id_type", Host::IDENT_FLEX);
@@ -791,17 +867,16 @@ public:
return (0);
}
-
- /// resets buffers used to store data received by callouts
+ /// Resets buffers used to store data received by callouts
void resetCalloutBuffers() {
callback_name_ = string("");
callback_qry_pkt4_.reset();
- callback_qry_pkt4_.reset();
+ callback_resp_pkt4_.reset();
+ callback_subnet4_.reset();
callback_lease4_.reset();
callback_deleted_lease4_.reset();
callback_hwaddr_.reset();
callback_clientid_.reset();
- callback_subnet4_.reset();
callback_subnet4collection_ = NULL;
callback_argument_names_.clear();
callback_qry_options_copy_ = false;
@@ -821,8 +896,8 @@ public:
return (stat->getInteger().first);
}
- /// pointer to Dhcpv4Srv that is used in tests
- NakedDhcpv4Srv* srv_;
+ /// Pointer to Dhcpv4Srv that is used in tests
+ boost::shared_ptr<NakedDhcpv4Srv> srv_;
/// Pointer to the IO service used in the tests.
static IOServicePtr io_service_;
@@ -832,16 +907,16 @@ public:
/// String name of the received callout
static string callback_name_;
- /// Client/query Pkt4 structure returned in the callout
+ /// Client's query Pkt4 structure returned in the callout
static Pkt4Ptr callback_qry_pkt4_;
- /// Server/response Pkt4 structure returned in the callout
+ /// Server's response Pkt4 structure returned in the callout
static Pkt4Ptr callback_resp_pkt4_;
- /// Lease4 structure returned in the leases4_committed callout
+ /// Pointer to lease4 structure returned in the leases4_committed callout
static Lease4Ptr callback_lease4_;
- /// Lease4 structure returned in the leases4_committed callout
+ /// Pointer to lease4 structure returned in the leases4_committed callout
static Lease4Ptr callback_deleted_lease4_;
/// Hardware address returned in the callout
@@ -866,7 +941,6 @@ public:
/// Flag indicating if copying retrieved options was enabled for
/// a response during callout execution.
static bool callback_resp_options_copy_;
-
};
// The following fields are used in testing pkt4_receive_callout.
@@ -876,11 +950,11 @@ string HooksDhcpv4SrvTest::callback_name_;
Pkt4Ptr HooksDhcpv4SrvTest::callback_qry_pkt4_;
Pkt4Ptr HooksDhcpv4SrvTest::callback_resp_pkt4_;
Subnet4Ptr HooksDhcpv4SrvTest::callback_subnet4_;
+const Subnet4Collection* HooksDhcpv4SrvTest::callback_subnet4collection_;
HWAddrPtr HooksDhcpv4SrvTest::callback_hwaddr_;
ClientIdPtr HooksDhcpv4SrvTest::callback_clientid_;
Lease4Ptr HooksDhcpv4SrvTest::callback_lease4_;
Lease4Ptr HooksDhcpv4SrvTest::callback_deleted_lease4_;
-const Subnet4Collection* HooksDhcpv4SrvTest::callback_subnet4collection_;
vector<string> HooksDhcpv4SrvTest::callback_argument_names_;
bool HooksDhcpv4SrvTest::callback_qry_options_copy_;
bool HooksDhcpv4SrvTest::callback_resp_options_copy_;
@@ -909,35 +983,35 @@ public:
/// that no libraries are loaded and that any marker files are deleted.
void reset() {
// Unload any previously-loaded libraries.
- HooksManager::unloadLibraries();
+ EXPECT_TRUE(HooksManager::unloadLibraries());
// Get rid of any marker files.
static_cast<void>(remove(LOAD_MARKER_FILE));
static_cast<void>(remove(UNLOAD_MARKER_FILE));
static_cast<void>(remove(SRV_CONFIG_MARKER_FILE));
+
CfgMgr::instance().clear();
}
};
-
-// Checks if callouts installed on pkt4_receive are indeed called and the
+// Checks if callouts installed on buffer4_receive are indeed called and the
// all necessary parameters are passed.
//
// Note that the test name does not follow test naming convention,
// but the proper hook name is "buffer4_receive".
-TEST_F(HooksDhcpv4SrvTest, Buffer4ReceiveSimple) {
+TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveSimple) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install buffer4_receive_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"buffer4_receive", buffer4_receive_callout));
// Let's create a simple DISCOVER
- Pkt4Ptr dis = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(dis);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
@@ -949,7 +1023,7 @@ TEST_F(HooksDhcpv4SrvTest, Buffer4ReceiveSimple) {
EXPECT_EQ("buffer4_receive", callback_name_);
// Check that pkt4 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_qry_pkt4_.get() == dis.get());
+ EXPECT_TRUE(callback_qry_pkt4_.get() == discover.get());
// Check that all expected parameters are there
vector<string> expected_argument_names;
@@ -961,7 +1035,7 @@ TEST_F(HooksDhcpv4SrvTest, Buffer4ReceiveSimple) {
EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(dis);
+ checkCalloutHandleReset(discover);
}
// Checks if callouts installed on buffer4_receive is able to change
@@ -1007,14 +1081,12 @@ TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveValueChange) {
}
// Checks if callouts installed on buffer4_receive is able to set skip flag that
-// will cause the server to not parse the packet. Even though the packet is valid,
-// the server should eventually drop it, because there won't be mandatory options
-// (or rather option objects) in it.
+// will cause the server to not process the packet (drop), even though it is valid.
TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveSkip) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install buffer4_receive_skip
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"buffer4_receive", buffer4_receive_skip));
@@ -1027,7 +1099,7 @@ TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveSkip) {
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
+ // In particular, it should call registered buffer4_receive callback.
srv_->run();
// Check that the server dropped the packet and did not produce any response
@@ -1038,12 +1110,12 @@ TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveSkip) {
}
// Checks if callouts installed on buffer4_receive is able to set drop flag that
-// will cause the server to drop the packet.
+// will cause the server to not process the packet (drop), even though it is valid.
TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveDrop) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install buffer4_receive_drop
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"buffer4_receive", buffer4_receive_drop));
@@ -1056,7 +1128,7 @@ TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveDrop) {
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
+ // In particular, it should call registered buffer4_receive callback.
srv_->run();
// Check that the server dropped the packet and did not produce any response
@@ -1080,10 +1152,10 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSimple) {
"pkt4_receive", pkt4_receive_callout));
// Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
@@ -1091,11 +1163,11 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSimple) {
// In particular, it should call registered pkt4_receive callback.
srv_->run();
- // check that the callback called is indeed the one we installed
+ // Check that the callback called is indeed the one we installed
EXPECT_EQ("pkt4_receive", callback_name_);
- // check that pkt4 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_qry_pkt4_.get() == sol.get());
+ // Check that pkt4 argument passing was successful and returned proper value
+ EXPECT_TRUE(callback_qry_pkt4_.get() == discover.get());
// Check that all expected parameters are there
vector<string> expected_argument_names;
@@ -1107,12 +1179,12 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSimple) {
EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
// Checks if callouts installed on pkt4_received is able to change
// the values and the parameters are indeed used by the server.
-TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_receive) {
+TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveValueChange) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
@@ -1121,10 +1193,10 @@ TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_receive) {
"pkt4_receive", pkt4_receive_change_clientid));
// Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
@@ -1132,7 +1204,7 @@ TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_receive) {
// In particular, it should call registered pkt4_receive callback.
srv_->run();
- // check that the server did send a response
+ // Check that the server did send a response
ASSERT_EQ(1, srv_->fake_sent_.size());
// Make sure that we received a response
@@ -1147,7 +1219,7 @@ TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_receive) {
EXPECT_TRUE(clientid->equals(expected));
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
// Checks if callouts installed on pkt4_received is able to delete
@@ -1157,15 +1229,15 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveDeleteClientId) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install pkt4_receive_delete_clientid
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"pkt4_receive", pkt4_receive_delete_clientid));
// Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
@@ -1177,7 +1249,7 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveDeleteClientId) {
ASSERT_EQ(0, srv_->fake_sent_.size());
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
// Checks if callouts installed on pkt4_received is able to set skip flag that
@@ -1186,15 +1258,15 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSkip) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install pkt4_receive_skip
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"pkt4_receive", pkt4_receive_skip));
// Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
@@ -1202,11 +1274,11 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSkip) {
// In particular, it should call registered pkt4_receive callback.
srv_->run();
- // check that the server dropped the packet and did not produce any response
+ // Check that the server dropped the packet and did not produce any response
ASSERT_EQ(0, srv_->fake_sent_.size());
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
// Checks if callouts installed on pkt4_received is able to set drop flag that
@@ -1215,15 +1287,15 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveDrop) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install pkt4_receive_drop
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"pkt4_receive", pkt4_receive_drop));
// Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
@@ -1231,34 +1303,33 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveDrop) {
// In particular, it should call registered pkt4_receive callback.
srv_->run();
- // check that the server dropped the packet and did not produce any response
+ // Check that the server dropped the packet and did not produce any response
ASSERT_EQ(0, srv_->fake_sent_.size());
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
-
// Checks if callouts installed on pkt4_send are indeed called and the
// all necessary parameters are passed.
TEST_F(HooksDhcpv4SrvTest, pkt4SendSimple) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install pkt4_send_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"pkt4_send", pkt4_send_callout));
// Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
+ // In particular, it should call registered pkt4_send callback.
srv_->run();
// Check that the callback called is indeed the one we installed
@@ -1268,18 +1339,17 @@ TEST_F(HooksDhcpv4SrvTest, pkt4SendSimple) {
ASSERT_EQ(1, srv_->fake_sent_.size());
Pkt4Ptr adv = srv_->fake_sent_.front();
- // Check that pkt4 argument passing was successful and returned proper value
+ // Check that pkt4 argument passing was successful and returned proper
+ // values
+ ASSERT_TRUE(callback_qry_pkt4_);
+ EXPECT_TRUE(callback_qry_pkt4_.get() == discover.get());
ASSERT_TRUE(callback_resp_pkt4_);
EXPECT_TRUE(callback_resp_pkt4_.get() == adv.get());
- // That that the query4 argument was correctly set to the Discover we sent.
- ASSERT_TRUE(callback_qry_pkt4_);
- EXPECT_TRUE(callback_qry_pkt4_.get() == sol.get());
-
// Check that all expected parameters are there
vector<string> expected_argument_names;
- expected_argument_names.push_back(string("response4"));
expected_argument_names.push_back(string("query4"));
+ expected_argument_names.push_back(string("response4"));
sort(callback_argument_names_.begin(), callback_argument_names_.end());
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(expected_argument_names == callback_argument_names_);
@@ -1289,7 +1359,7 @@ TEST_F(HooksDhcpv4SrvTest, pkt4SendSimple) {
EXPECT_TRUE(callback_resp_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
// Checks if callouts installed on pkt4_send is able to change
@@ -1298,23 +1368,23 @@ TEST_F(HooksDhcpv4SrvTest, pkt4SendValueChange) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install pkt4_send_change_serverid
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"pkt4_send", pkt4_send_change_serverid));
// Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
+ // In particular, it should call registered pkt4_send callback.
srv_->run();
- // check that the server did send a response
+ // Check that the server did send a response
ASSERT_EQ(1, srv_->fake_sent_.size());
// Make sure that we received a response
@@ -1329,7 +1399,7 @@ TEST_F(HooksDhcpv4SrvTest, pkt4SendValueChange) {
EXPECT_TRUE(clientid->equals(expected));
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
// Checks if callouts installed on pkt4_send is able to delete
@@ -1340,20 +1410,20 @@ TEST_F(HooksDhcpv4SrvTest, pkt4SendDeleteServerId) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install pkt4_send_delete_serverid
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"pkt4_send", pkt4_send_delete_serverid));
// Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
+ // In particular, it should call registered pkt4_send callback.
srv_->run();
// Check that the server indeed sent a malformed ADVERTISE
@@ -1367,24 +1437,24 @@ TEST_F(HooksDhcpv4SrvTest, pkt4SendDeleteServerId) {
EXPECT_FALSE(adv->getOption(DHO_DHCP_SERVER_IDENTIFIER));
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
// Checks if callouts installed on pkt4_skip is able to set skip flag that
// will cause the server to not process the packet (drop), even though it is valid.
-TEST_F(HooksDhcpv4SrvTest, skip_pkt4_send) {
+TEST_F(HooksDhcpv4SrvTest, pkt4SendSkip) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install pkt4_send_skip
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"pkt4_send", pkt4_send_skip));
// Let's create a simple REQUEST
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
@@ -1392,33 +1462,35 @@ TEST_F(HooksDhcpv4SrvTest, skip_pkt4_send) {
// In particular, it should call registered pkt4_send callback.
srv_->run();
- // Check that the server sent the message
+ // Check that the server send the packet
ASSERT_EQ(1, srv_->fake_sent_.size());
// Get the first packet and check that it has zero length (i.e. the server
// did not do packing on its own)
Pkt4Ptr sent = srv_->fake_sent_.front();
+
+ // The actual size of sent packet should be 0
EXPECT_EQ(0, sent->getBuffer().getLength());
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
// Checks if callouts installed on pkt4_drop is able to set drop flag that
// will cause the server to not process the packet (drop), even though it is valid.
-TEST_F(HooksDhcpv4SrvTest, drop_pkt4_send) {
+TEST_F(HooksDhcpv4SrvTest, pkt4SendDrop) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install pkt4_send_drop
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"pkt4_send", pkt4_send_drop));
// Let's create a simple REQUEST
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
@@ -1426,11 +1498,11 @@ TEST_F(HooksDhcpv4SrvTest, drop_pkt4_send) {
// In particular, it should call registered pkt4_send callback.
srv_->run();
- // Check that the server did not the message
- ASSERT_EQ(0, srv_->fake_sent_.size());
+ // Check that the server does not send the packet
+ EXPECT_EQ(0, srv_->fake_sent_.size());
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
// Checks if callouts installed on buffer4_send are indeed called and the
@@ -1439,7 +1511,7 @@ TEST_F(HooksDhcpv4SrvTest, buffer4SendSimple) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install buffer4_send_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"buffer4_send", buffer4_send_callout));
@@ -1452,7 +1524,7 @@ TEST_F(HooksDhcpv4SrvTest, buffer4SendSimple) {
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
+ // In particular, it should call registered buffer4_send callback.
srv_->run();
// Check that the callback called is indeed the one we installed
@@ -1479,11 +1551,11 @@ TEST_F(HooksDhcpv4SrvTest, buffer4SendSimple) {
// Checks if callouts installed on buffer4_send are indeed called and that
// the output buffer can be changed.
-TEST_F(HooksDhcpv4SrvTest, buffer4Send) {
+TEST_F(HooksDhcpv4SrvTest, buffer4SendChange) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install buffer4_send_change_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"buffer4_send", buffer4_send_change_callout));
@@ -1496,7 +1568,7 @@ TEST_F(HooksDhcpv4SrvTest, buffer4Send) {
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
+ // In particular, it should call registered buffer4_send callback.
srv_->run();
// Check that there is one packet sent
@@ -1517,9 +1589,9 @@ TEST_F(HooksDhcpv4SrvTest, buffer4SendSkip) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install buffer4_send_skip
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer4_send", skip_callout));
+ "buffer4_send", buffer4_send_skip));
// Let's create a simple DISCOVER
Pkt4Ptr discover = generateSimpleDiscover();
@@ -1530,9 +1602,12 @@ TEST_F(HooksDhcpv4SrvTest, buffer4SendSkip) {
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
+ // In particular, it should call registered buffer4_send callback.
srv_->run();
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("buffer4_send", callback_name_);
+
// Check that there is no packet sent.
ASSERT_EQ(0, srv_->fake_sent_.size());
@@ -1546,9 +1621,9 @@ TEST_F(HooksDhcpv4SrvTest, buffer4SendDrop) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
+ // Install buffer4_send_drop
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer4_send", drop_callout));
+ "buffer4_send", buffer4_send_drop));
// Let's create a simple DISCOVER
Pkt4Ptr discover = generateSimpleDiscover();
@@ -1559,17 +1634,19 @@ TEST_F(HooksDhcpv4SrvTest, buffer4SendDrop) {
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
+ // In particular, it should call registered buffer4_send callback.
srv_->run();
- // Check that there is no packet sent.
- ASSERT_EQ(0, srv_->fake_sent_.size());
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("buffer4_send", callback_name_);
+
+ // Check that there is no packet sent
+ EXPECT_EQ(0, srv_->fake_sent_.size());
// Check if the callout handle state was reset after the callout.
checkCalloutHandleReset(discover);
}
-
// This test checks if subnet4_select callout is triggered and reports
// valid parameters
TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
@@ -1606,29 +1683,29 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
// Commit the config
CfgMgr::instance().commit();
- // Install pkt4_receive_callout
+ // Install subnet4_select_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"subnet4_select", subnet4_select_callout));
// Prepare discover packet. Server should select first subnet for it
- Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
- sol->setRemoteAddr(IOAddress("192.0.2.1"));
- sol->setIface("eth1");
- sol->setIndex(ETH1_INDEX);
+ Pkt4Ptr discover = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
+ discover->setRemoteAddr(IOAddress("192.0.2.1"));
+ discover->setIface("eth1");
+ discover->setIndex(ETH1_INDEX);
OptionPtr clientid = generateClientId();
- sol->addOption(clientid);
+ discover->addOption(clientid);
// Pass it to the server and get an advertise
- Pkt4Ptr adv = srv_->processDiscover(sol);
+ Pkt4Ptr adv = srv_->processDiscover(discover);
- // check if we get response at all
+ // Check if we get response at all
ASSERT_TRUE(adv);
// Check that the callback called is indeed the one we installed
EXPECT_EQ("subnet4_select", callback_name_);
// Check that pkt4 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_qry_pkt4_.get() == sol.get());
+ EXPECT_TRUE(callback_qry_pkt4_.get() == discover.get());
const Subnet4Collection* exp_subnets =
CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
@@ -1636,7 +1713,7 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
// The server is supposed to pick the first subnet, because of matching
// interface. Check that the value is reported properly.
ASSERT_TRUE(callback_subnet4_);
- EXPECT_EQ(exp_subnets->begin()->get(), callback_subnet4_.get());
+ EXPECT_EQ(callback_subnet4_.get(), exp_subnets->begin()->get());
// Server is supposed to report two subnets
ASSERT_EQ(exp_subnets->size(), callback_subnet4collection_->size());
@@ -1650,7 +1727,7 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
// This test checks if callout installed on subnet4_select hook point can pick
@@ -1688,22 +1765,22 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectChange) {
CfgMgr::instance().commit();
- // Install a callout
+ // Install subnet4_select_different_subnet
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "subnet4_select", subnet4_select_different_subnet_callout));
+ "subnet4_select", subnet4_select_different_subnet));
// Prepare discover packet. Server should select first subnet for it
- Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
- sol->setRemoteAddr(IOAddress("192.0.2.1"));
- sol->setIface("eth0");
- sol->setIndex(ETH0_INDEX);
+ Pkt4Ptr discover = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
+ discover->setRemoteAddr(IOAddress("192.0.2.1"));
+ discover->setIface("eth0");
+ discover->setIndex(ETH0_INDEX);
OptionPtr clientid = generateClientId();
- sol->addOption(clientid);
+ discover->addOption(clientid);
// Pass it to the server and get an advertise
- Pkt4Ptr adv = srv_->processDiscover(sol);
+ Pkt4Ptr adv = srv_->processDiscover(discover);
- // check if we get response at all
+ // Check if we get response at all
ASSERT_TRUE(adv);
// The response should have an address from second pool, so let's check it
@@ -1723,7 +1800,35 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectChange) {
EXPECT_TRUE((*subnet)->inPool(Lease::TYPE_V4, addr));
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
+}
+
+// Checks that subnet4_select is able to drop the packet.
+TEST_F(HooksDhcpv4SrvTest, subnet4SelectDrop) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ // Install subnet4_select_drop
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "subnet4_select", subnet4_select_drop));
+
+ // Let's create a simple DISCOVER
+ Pkt4Ptr discover = generateSimpleDiscover();
+
+ // Simulate that we have received that traffic
+ srv_->fakeReceive(discover);
+
+ // Server will now process to run its normal loop, but instead of calling
+ // IfaceMgr::receive4(), it will read all packets from the list set by
+ // fakeReceive()
+ // In particular, it should call registered subnet4_select callback.
+ srv_->run();
+
+ // Check that the server dropped the packet and did not produce any response
+ ASSERT_EQ(0, srv_->fake_sent_.size());
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(discover);
}
// This test verifies that the leases4_committed hook point is not triggered
@@ -1732,10 +1837,10 @@ TEST_F(HooksDhcpv4SrvTest, leases4CommittedDiscover) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
+ // Install leases4_committed callout
ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"leases4_committed", leases4_committed_callout));
-
Dhcp4Client client(Dhcp4Client::SELECTING);
client.setIfaceName("eth1");
client.setIfaceIndex(ETH1_INDEX);
@@ -1760,7 +1865,6 @@ TEST_F(HooksDhcpv4SrvTest, leases4CommittedInform) {
ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"leases4_committed", leases4_committed_callout));
-
Dhcp4Client client(Dhcp4Client::SELECTING);
client.useRelay();
ASSERT_NO_THROW(client.doInform());
@@ -1775,172 +1879,6 @@ TEST_F(HooksDhcpv4SrvTest, leases4CommittedInform) {
checkCalloutHandleReset(client.getContext().query_);
}
-// This test verifies that incoming (positive) REQUEST/Renewing can be handled
-// properly and that callout installed on lease4_renew is triggered with
-// expected parameters.
-TEST_F(HooksDhcpv4SrvTest, lease4RenewSimple) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
-
- const IOAddress addr("192.0.2.106");
- const uint32_t temp_valid = 100;
- const time_t temp_timestamp = time(NULL) - 10;
-
- // Install a callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_renew", lease4_renew_callout));
-
- // Generate client-id also sets client_id_ member
- OptionPtr clientid = generateClientId();
-
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
-
- // let's create a lease and put it in the LeaseMgr
- uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
- HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
- Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
- &client_id_->getDuid()[0], client_id_->getDuid().size(),
- temp_valid, temp_timestamp, subnet_->getID()));
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
-
- // Check that the lease is really in the database
- Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
- ASSERT_TRUE(l);
-
- // Let's create a RENEW
- Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
- req->setRemoteAddr(IOAddress(addr));
- req->setYiaddr(addr);
- req->setCiaddr(addr); // client's address
- req->setIface("eth0");
- req->setIndex(ETH0_INDEX);
- req->setHWAddr(hwaddr2);
-
- req->addOption(clientid);
- req->addOption(srv_->getServerID());
-
- // Pass it to the server and hope for a REPLY
- Pkt4Ptr ack = srv_->processRequest(req);
-
- // Check if we get response at all
- checkResponse(ack, DHCPACK, 1234);
-
- // Check that the lease is really in the database
- l = checkLease(ack, clientid, req->getHWAddr(), addr);
- ASSERT_TRUE(l);
-
- // Check that preferred, valid and cltt were really updated
- EXPECT_EQ(l->valid_lft_, subnet_->getValid());
-
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease4_renew", callback_name_);
-
- // Check that query4 argument passing was successful and
- // returned proper value
- EXPECT_TRUE(callback_qry_pkt4_.get() == req.get());
-
- // Check that hwaddr parameter is passed properly
- ASSERT_TRUE(callback_hwaddr_);
- EXPECT_TRUE(*callback_hwaddr_ == *req->getHWAddr());
-
- // Check that the subnet is passed properly
- ASSERT_TRUE(callback_subnet4_);
- EXPECT_EQ(callback_subnet4_->toText(), subnet_->toText());
-
- ASSERT_TRUE(callback_clientid_);
- ASSERT_TRUE(client_id_);
- EXPECT_TRUE(*client_id_ == *callback_clientid_);
-
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query4");
- expected_argument_names.push_back("subnet4");
- expected_argument_names.push_back("clientid");
- expected_argument_names.push_back("hwaddr");
- expected_argument_names.push_back("lease4");
- sort(callback_argument_names_.begin(), callback_argument_names_.end());
- sort(expected_argument_names.begin(), expected_argument_names.end());
- EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
-
- Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(addr);
- EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(lease));
-
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
-
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(req);
-}
-
-// This test verifies that a callout installed on lease4_renew can trigger
-// the server to not renew a lease.
-TEST_F(HooksDhcpv4SrvTest, lease4RenewSkip) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
-
- const IOAddress addr("192.0.2.106");
- const uint32_t temp_valid = 100;
- const time_t temp_timestamp = time(NULL) - 10;
-
- // Install a callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_renew", skip_callout));
-
- // Generate client-id also sets client_id_ member
- OptionPtr clientid = generateClientId();
-
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
-
- // let's create a lease and put it in the LeaseMgr
- uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
- HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
- Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
- &client_id_->getDuid()[0], client_id_->getDuid().size(),
- temp_valid, temp_timestamp, subnet_->getID()));
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
-
- // Check that the lease is really in the database
- Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
- ASSERT_TRUE(l);
-
- // Check that preferred, valid and cltt really set.
- // Constructed lease looks as if it was assigned 10 seconds ago
- EXPECT_EQ(l->valid_lft_, temp_valid);
- EXPECT_EQ(l->cltt_, temp_timestamp);
-
- // Let's create a RENEW
- Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
- req->setRemoteAddr(IOAddress(addr));
- req->setYiaddr(addr);
- req->setCiaddr(addr); // client's address
- req->setIface("eth0");
- req->setIndex(ETH0_INDEX);
- req->setHWAddr(hwaddr2);
-
- req->addOption(clientid);
- req->addOption(srv_->getServerID());
-
- // Pass it to the server and hope for a REPLY
- Pkt4Ptr ack = srv_->processRequest(req);
- ASSERT_TRUE(ack);
-
- // Check that the lease is really in the database
- l = checkLease(ack, clientid, req->getHWAddr(), addr);
- ASSERT_TRUE(l);
-
- // Check that valid and cltt were NOT updated
- EXPECT_EQ(temp_valid, l->valid_lft_);
- EXPECT_EQ(temp_timestamp, l->cltt_);
-
- Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(addr);
- EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(lease));
-
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(req);
-}
-
// This test verifies that the callout installed on the leases4_committed hook
// point is executed as a result of DHCPREQUEST message sent to allocate new
// lease or renew an existing lease.
@@ -1951,7 +1889,6 @@ TEST_F(HooksDhcpv4SrvTest, leases4CommittedRequest) {
ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"leases4_committed", leases4_committed_callout));
-
Dhcp4Client client(Dhcp4Client::SELECTING);
client.setIfaceName("eth1");
client.setIfaceIndex(ETH1_INDEX);
@@ -2055,9 +1992,102 @@ TEST_F(HooksDhcpv4SrvTest, leases4CommittedRequest) {
EXPECT_FALSE(callback_deleted_lease4_);
}
+// This test verifies that the leases4_committed callout is executed
+// with declined leases as argument when DHCPDECLINE is processed.
+TEST_F(HooksDhcpv4SrvTest, leases4CommittedDecline) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases4_committed", leases4_committed_callout));
+
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ client.useRelay();
+ ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<IOAddress>(new IOAddress("192.0.2.100"))));
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ resetCalloutBuffers();
+
+ ASSERT_NO_THROW(client.doDecline());
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases4_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query4");
+ expected_argument_names.push_back("deleted_leases4");
+ expected_argument_names.push_back("leases4");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // No new allocations.
+ ASSERT_TRUE(callback_lease4_);
+ EXPECT_EQ("192.0.2.100", callback_lease4_->addr_.toText());
+ EXPECT_EQ(Lease::STATE_DECLINED, callback_lease4_->state_);
+
+ // Released lease should be returned.
+ EXPECT_FALSE(callback_deleted_lease4_);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client.getContext().query_);
+}
+
+// This test verifies that the leases4_committed callout is executed
+// with deleted leases as argument when DHCPRELEASE is processed.
+TEST_F(HooksDhcpv4SrvTest, leases4CommittedRelease) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases4_committed", leases4_committed_callout));
+
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ client.setIfaceName("eth1");
+ client.setIfaceIndex(ETH1_INDEX);
+ ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<IOAddress>(new IOAddress("192.0.2.100"))));
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ resetCalloutBuffers();
+
+ ASSERT_NO_THROW(client.doRelease());
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases4_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query4");
+ expected_argument_names.push_back("deleted_leases4");
+ expected_argument_names.push_back("leases4");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // No new allocations.
+ EXPECT_FALSE(callback_lease4_);
+
+ // Released lease should be returned.
+ ASSERT_TRUE(callback_deleted_lease4_);
+ EXPECT_EQ("192.0.2.100", callback_deleted_lease4_->addr_.toText());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client.getContext().query_);
+}
// This test verifies that the callout installed on the leases4_committed hook
-// point is executed as a result of DHCPREQUEST message sent to reuse
-// an existing lease.
+// point is executed as a result of DHCPREQUEST message sent to reuse an
+// existing lease.
TEST_F(HooksDhcpv4SrvTest, leases4CommittedCache) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
@@ -2065,7 +2095,6 @@ TEST_F(HooksDhcpv4SrvTest, leases4CommittedCache) {
ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"leases4_committed", leases4_committed_callout));
-
// Modify the subnet to reuse leases.
subnet_->setCacheThreshold(.25);
@@ -2213,16 +2242,185 @@ TEST_F(HooksDhcpv4SrvTest, leases4CommittedParkRequests) {
checkCalloutHandleReset(client2.getContext().query_);
}
+// This test verifies that incoming (positive) REQUEST/Renewing can be handled
+// properly and that callout installed on lease4_renew is triggered with
+// expected parameters.
+TEST_F(HooksDhcpv4SrvTest, lease4RenewSimple) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ const IOAddress addr("192.0.2.106");
+ const uint32_t temp_valid = 100;
+ const time_t temp_timestamp = time(NULL) - 10;
+
+ // Install lease4_renew_callout
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease4_renew", lease4_renew_callout));
+
+ // Generate client-id also sets client_id_ member
+ OptionPtr clientid = generateClientId();
+
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
+
+ // let's create a lease and put it in the LeaseMgr
+ uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe };
+ HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
+ Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
+ &client_id_->getDuid()[0], client_id_->getDuid().size(),
+ temp_valid, temp_timestamp, subnet_->getID()));
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
+
+ // Check that the lease is really in the database
+ Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
+ ASSERT_TRUE(l);
+
+ // Let's create a RENEW
+ Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
+ req->setRemoteAddr(IOAddress(addr));
+ req->setYiaddr(addr);
+ req->setCiaddr(addr); // client's address
+ req->setIface("eth0");
+ req->setIndex(ETH0_INDEX);
+ req->setHWAddr(hwaddr2);
+
+ req->addOption(clientid);
+ req->addOption(srv_->getServerID());
+
+ // Pass it to the server and hope for a REPLY
+ Pkt4Ptr ack = srv_->processRequest(req);
+
+ // Check if we get response at all
+ checkResponse(ack, DHCPACK, 1234);
+
+ // Check that the lease is really in the database
+ l = checkLease(ack, clientid, req->getHWAddr(), addr);
+ ASSERT_TRUE(l);
+
+ // Check that preferred, valid and cltt were really updated
+ EXPECT_EQ(l->valid_lft_, subnet_->getValid());
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("lease4_renew", callback_name_);
+
+ // Check that query4 argument passing was successful and
+ // returned proper value
+ EXPECT_TRUE(callback_qry_pkt4_.get() == req.get());
+
+ // Check that hwaddr parameter is passed properly
+ ASSERT_TRUE(callback_hwaddr_);
+ EXPECT_TRUE(*callback_hwaddr_ == *req->getHWAddr());
+
+ // Check that the subnet is passed properly
+ ASSERT_TRUE(callback_subnet4_);
+ EXPECT_EQ(callback_subnet4_->toText(), subnet_->toText());
+
+ ASSERT_TRUE(callback_clientid_);
+ ASSERT_TRUE(client_id_);
+ EXPECT_TRUE(*client_id_ == *callback_clientid_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query4");
+ expected_argument_names.push_back("subnet4");
+ expected_argument_names.push_back("clientid");
+ expected_argument_names.push_back("hwaddr");
+ expected_argument_names.push_back("lease4");
+ sort(callback_argument_names_.begin(), callback_argument_names_.end());
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(addr);
+ EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(lease));
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(req);
+}
+
+// This test verifies that a callout installed on lease4_renew can trigger
+// the server to not renew a lease.
+TEST_F(HooksDhcpv4SrvTest, lease4RenewSkip) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ const IOAddress addr("192.0.2.106");
+ const uint32_t temp_valid = 100;
+ const time_t temp_timestamp = time(NULL) - 10;
+
+ // Install lease4_renew_skip_callout
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease4_renew", lease4_renew_skip_callout));
+
+ // Generate client-id also sets client_id_ member
+ OptionPtr clientid = generateClientId();
+
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
+
+ // let's create a lease and put it in the LeaseMgr
+ uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe };
+ HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
+ Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
+ &client_id_->getDuid()[0], client_id_->getDuid().size(),
+ temp_valid, temp_timestamp, subnet_->getID()));
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
+
+ // Check that the lease is really in the database
+ Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
+ ASSERT_TRUE(l);
+
+ // Check that preferred, valid and cltt really set.
+ // Constructed lease looks as if it was assigned 10 seconds ago
+ EXPECT_EQ(l->valid_lft_, temp_valid);
+ EXPECT_EQ(l->cltt_, temp_timestamp);
+
+ // Let's create a RENEW
+ Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
+ req->setRemoteAddr(IOAddress(addr));
+ req->setYiaddr(addr);
+ req->setCiaddr(addr); // client's address
+ req->setIface("eth0");
+ req->setIndex(ETH0_INDEX);
+ req->setHWAddr(hwaddr2);
+
+ req->addOption(clientid);
+ req->addOption(srv_->getServerID());
+
+ // Pass it to the server and hope for a REPLY
+ Pkt4Ptr ack = srv_->processRequest(req);
+ ASSERT_TRUE(ack);
+
+ // Check that the lease is really in the database
+ l = checkLease(ack, clientid, req->getHWAddr(), addr);
+ ASSERT_TRUE(l);
+
+ // Check that valid and cltt were NOT updated
+ EXPECT_EQ(temp_valid, l->valid_lft_);
+ EXPECT_EQ(temp_timestamp, l->cltt_);
+
+ Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(addr);
+ EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(lease));
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(req);
+}
+
// This test verifies that valid RELEASE triggers lease4_release callouts
TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimple) {
IfaceMgrTestConfig test_config(true);
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setFlushReclaimedTimerWaitTime(0);
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setHoldReclaimedTime(0);
IfaceMgr::instance().openSockets4();
const IOAddress addr("192.0.2.106");
const uint32_t temp_valid = 100;
const time_t temp_timestamp = time(NULL) - 10;
- // Install a callout
+ // Install lease4_release_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"lease4_release", lease4_release_callout));
@@ -2233,7 +2431,7 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimple) {
ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
// Let's create a lease and put it in the LeaseMgr
- uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
+ uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe };
HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
Lease4Ptr used(new Lease4(addr, hw,
&client_id_->getDuid()[0], client_id_->getDuid().size(),
@@ -2262,18 +2460,16 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimple) {
EXPECT_FALSE(l);
// Try to get the lease by hardware address
- // @todo: Uncomment this once trac2592 is implemented
- // Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
- // EXPECT_EQ(leases.size(), 0);
+ Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*hw);
+ EXPECT_EQ(leases.size(), 0);
// Try to get it by hw/subnet_id combination
- l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
+ l = LeaseMgrFactory::instance().getLease4(*hw, subnet_->getID());
EXPECT_FALSE(l);
// Try by client-id
- // @todo: Uncomment this once trac2592 is implemented
- //Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*client_id_);
- //EXPECT_EQ(leases.size(), 0);
+ leases = LeaseMgrFactory::instance().getLease4(*client_id_);
+ EXPECT_EQ(leases.size(), 0);
// Try by client-id/subnet-id
l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
@@ -2302,9 +2498,8 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimple) {
checkCalloutHandleReset(rel);
}
-// This test verifies that skip flag returned by a callout installed on the
-// lease4_release hook point will keep the lease
-TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
+// This test verifies that valid RELEASE triggers lease4_release callouts
+TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimpleNoDelete) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
@@ -2312,9 +2507,9 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
const uint32_t temp_valid = 100;
const time_t temp_timestamp = time(NULL) - 10;
- // Install a callout
+ // Install lease4_release_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_release", skip_callout));
+ "lease4_release", lease4_release_callout));
// Generate client-id also duid_
OptionPtr clientid = generateClientId();
@@ -2323,7 +2518,7 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
// Let's create a lease and put it in the LeaseMgr
- uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
+ uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe };
HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
Lease4Ptr used(new Lease4(addr, hw,
&client_id_->getDuid()[0], client_id_->getDuid().size(),
@@ -2338,7 +2533,7 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
// Generate client-id also duid_
Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
rel->setRemoteAddr(addr);
- rel->setYiaddr(addr);
+ rel->setCiaddr(addr);
rel->addOption(clientid);
rel->addOption(srv_->getServerID());
rel->setHWAddr(hw);
@@ -2347,76 +2542,116 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
// Note: this is no response to RELEASE in DHCPv4
EXPECT_NO_THROW(srv_->processRelease(rel));
- // The lease should be still there
+ // The lease should not be gone from LeaseMgr
l = LeaseMgrFactory::instance().getLease4(addr);
EXPECT_TRUE(l);
- // Try by client-id/subnet-id
- l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
- EXPECT_TRUE(l);
-
- // Try to get the lease by hardware address, should succeed
+ // Try to get the lease by hardware address
Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*hw);
EXPECT_EQ(leases.size(), 1);
- // Try by client-id, should be successful as well.
+ // Try to get it by hw/subnet_id combination
+ l = LeaseMgrFactory::instance().getLease4(*hw, subnet_->getID());
+ EXPECT_TRUE(l);
+
+ // Try by client-id
leases = LeaseMgrFactory::instance().getLease4(*client_id_);
EXPECT_EQ(leases.size(), 1);
+ // Try by client-id/subnet-id
+ l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
+ EXPECT_TRUE(l);
+
+ // Ok, the lease is *really* there.
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("lease4_release", callback_name_);
+
+ // Check that pkt4 argument passing was successful and returned proper value
+ EXPECT_TRUE(callback_qry_pkt4_.get() == rel.get());
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query4");
+ expected_argument_names.push_back("lease4");
+ sort(callback_argument_names_.begin(), callback_argument_names_.end());
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
// Check if the callout handle state was reset after the callout.
checkCalloutHandleReset(rel);
}
-// This test verifies that the leases4_committed callout is executed
-// with deleted leases as argument when DHCPRELEASE is processed.
-TEST_F(HooksDhcpv4SrvTest, leases4CommittedRelease) {
+// This test verifies that skip flag returned by a callout installed on the
+// lease4_release hook point will keep the lease.
+TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases4_committed", leases4_committed_callout));
+ const IOAddress addr("192.0.2.106");
+ const uint32_t temp_valid = 100;
+ const time_t temp_timestamp = time(NULL) - 10;
+ // Install lease4_release_skip
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease4_release", lease4_release_skip));
- Dhcp4Client client(Dhcp4Client::SELECTING);
- client.setIfaceName("eth1");
- client.setIfaceIndex(ETH1_INDEX);
- ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<IOAddress>(new IOAddress("192.0.2.100"))));
+ // Generate client-id also duid_
+ OptionPtr clientid = generateClientId();
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
- resetCalloutBuffers();
+ // Let's create a lease and put it in the LeaseMgr
+ uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe };
+ HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
+ Lease4Ptr used(new Lease4(addr, hw,
+ &client_id_->getDuid()[0], client_id_->getDuid().size(),
+ temp_valid, temp_timestamp, subnet_->getID()));
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
- ASSERT_NO_THROW(client.doRelease());
+ // Check that the lease is really in the database
+ Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
+ ASSERT_TRUE(l);
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases4_committed", callback_name_);
+ // Let's create a RELEASE
+ // Generate client-id also duid_
+ Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
+ rel->setRemoteAddr(addr);
+ rel->setYiaddr(addr);
+ rel->addOption(clientid);
+ rel->addOption(srv_->getServerID());
+ rel->setHWAddr(hw);
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query4");
- expected_argument_names.push_back("deleted_leases4");
- expected_argument_names.push_back("leases4");
+ // Pass it to the server and hope for a REPLY
+ // Note: this is no response to RELEASE in DHCPv4
+ EXPECT_NO_THROW(srv_->processRelease(rel));
- sort(expected_argument_names.begin(), expected_argument_names.end());
- EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+ // The lease should be still there
+ l = LeaseMgrFactory::instance().getLease4(addr);
+ EXPECT_TRUE(l);
- // No new allocations.
- EXPECT_FALSE(callback_lease4_);
+ // Try by client-id/subnet-id
+ l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
+ EXPECT_TRUE(l);
- // Released lease should be returned.
- ASSERT_TRUE(callback_deleted_lease4_);
- EXPECT_EQ("192.0.2.100", callback_deleted_lease4_->addr_.toText());
+ // Try to get the lease by hardware address, should succeed
+ Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*hw);
+ EXPECT_EQ(leases.size(), 1);
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
+ // Try by client-id, should be successful as well.
+ leases = LeaseMgrFactory::instance().getLease4(*client_id_);
+ EXPECT_EQ(leases.size(), 1);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
+ checkCalloutHandleReset(rel);
}
// This test verifies that drop flag returned by a callout installed on the
-// lease4_release hook point will keep the lease
+// lease4_release hook point will keep the lease.
TEST_F(HooksDhcpv4SrvTest, lease4ReleaseDrop) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
@@ -2425,9 +2660,9 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseDrop) {
const uint32_t temp_valid = 100;
const time_t temp_timestamp = time(NULL) - 10;
- // Install a callout
+ // Install lease4_release_drop
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_release", drop_callout));
+ "lease4_release", lease4_release_drop));
// Generate client-id also duid_
OptionPtr clientid = generateClientId();
@@ -2436,7 +2671,7 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseDrop) {
ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
// Let's create a lease and put it in the LeaseMgr
- uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
+ uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe };
HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
Lease4Ptr used(new Lease4(addr, hw,
&client_id_->getDuid()[0], client_id_->getDuid().size(),
@@ -2480,12 +2715,13 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseDrop) {
checkCalloutHandleReset(rel);
}
-// Checks that decline4 hooks (lease4_decline) are triggered properly.
-TEST_F(HooksDhcpv4SrvTest, HooksDecline) {
+// This test checks that the basic decline hook (lease4_decline) is
+// triggered properly.
+TEST_F(HooksDhcpv4SrvTest, lease4DeclineSimple) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install a callout
+ // Install lease4_decline callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"lease4_decline", lease4_decline_callout));
@@ -2531,14 +2767,14 @@ TEST_F(HooksDhcpv4SrvTest, HooksDecline) {
checkCalloutHandleReset(client.getContext().query_);
}
-// Checks that decline4 hook is able to skip the packet.
-TEST_F(HooksDhcpv4SrvTest, HooksDeclineSkip) {
+// Test that the lease4_decline hook point can handle SKIP status.
+TEST_F(HooksDhcpv4SrvTest, lease4DeclineSkip) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install a callout
+ // Install lease4_decline_skip callout. It will set the status to skip
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_decline", lease4_decline_skip_callout));
+ "lease4_decline", lease4_decline_skip));
HooksManager::setTestMode(true);
@@ -2581,14 +2817,14 @@ TEST_F(HooksDhcpv4SrvTest, HooksDeclineSkip) {
checkCalloutHandleReset(client.getContext().query_);
}
-// Checks that decline4 hook is able to drop the packet.
-TEST_F(HooksDhcpv4SrvTest, HooksDeclineDrop) {
+// Test that the lease4_decline hook point can handle DROP status.
+TEST_F(HooksDhcpv4SrvTest, lease4DeclineDrop) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
- // Install a callout
+ // Install lease4_decline_drop callout. It will set the status to drop
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_decline", lease4_decline_drop_callout));
+ "lease4_decline", lease4_decline_drop));
HooksManager::setTestMode(true);
@@ -2631,57 +2867,9 @@ TEST_F(HooksDhcpv4SrvTest, HooksDeclineDrop) {
checkCalloutHandleReset(client.getContext().query_);
}
-// This test verifies that the leases4_committed callout is executed
-// with declined leases as argument when DHCPDECLINE is processed.
-TEST_F(HooksDhcpv4SrvTest, leases4CommittedDecline) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
-
- ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases4_committed", leases4_committed_callout));
-
-
- Dhcp4Client client(Dhcp4Client::SELECTING);
- client.useRelay();
- ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<IOAddress>(new IOAddress("192.0.2.100"))));
-
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
-
- resetCalloutBuffers();
-
- ASSERT_NO_THROW(client.doDecline());
-
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases4_committed", callback_name_);
-
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query4");
- expected_argument_names.push_back("deleted_leases4");
- expected_argument_names.push_back("leases4");
-
- sort(expected_argument_names.begin(), expected_argument_names.end());
- EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
-
- // No new allocations.
- ASSERT_TRUE(callback_lease4_);
- EXPECT_EQ("192.0.2.100", callback_lease4_->addr_.toText());
- EXPECT_EQ(Lease::STATE_DECLINED, callback_lease4_->state_);
-
- // Released lease should be returned.
- EXPECT_FALSE(callback_deleted_lease4_);
-
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
-
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
-}
-
// Checks if callout installed on host4_identifier can generate an
// identifier and whether that identifier is actually used.
-TEST_F(HooksDhcpv4SrvTest, host4_identifier) {
+TEST_F(HooksDhcpv4SrvTest, host4Identifier) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
@@ -2725,10 +2913,10 @@ TEST_F(HooksDhcpv4SrvTest, host4_identifier) {
"host4_identifier", host4_identifier_foo_callout));
// Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
@@ -2747,12 +2935,12 @@ TEST_F(HooksDhcpv4SrvTest, host4_identifier) {
EXPECT_EQ("192.0.2.201", adv->getYiaddr().toText());
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
-// Checks if callout installed on host4_identifier can generate identifier of
+// Checks if callout installed on host4_identifier can generate an identifier of
// other type. This particular callout always returns hwaddr.
-TEST_F(HooksDhcpv4SrvTest, host4_identifier_hwaddr) {
+TEST_F(HooksDhcpv4SrvTest, host4IdentifierHWAddr) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
@@ -2796,10 +2984,10 @@ TEST_F(HooksDhcpv4SrvTest, host4_identifier_hwaddr) {
"host4_identifier", host4_identifier_hwaddr_callout));
// Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
+ Pkt4Ptr discover = generateSimpleDiscover();
// Simulate that we have received that traffic
- srv_->fakeReceive(sol);
+ srv_->fakeReceive(discover);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
@@ -2818,10 +3006,9 @@ TEST_F(HooksDhcpv4SrvTest, host4_identifier_hwaddr) {
EXPECT_EQ("192.0.2.201", adv->getYiaddr().toText());
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(sol);
+ checkCalloutHandleReset(discover);
}
-
// Verifies that libraries are unloaded by server destruction
// The callout libraries write their library index number to a marker
// file upon load and unload, making it simple to test whether or not
@@ -2993,7 +3180,7 @@ TEST_F(LoadUnloadDhcpv4SrvTest, Dhcpv4SrvConfigured) {
}
// This test verifies that parked-packet-limit is properly enforced.
-TEST_F(HooksDhcpv4SrvTest, parkedPacketLimit) {
+TEST_F(HooksDhcpv4SrvTest, leases4ParkedPacketLimit) {
IfaceMgrTestConfig test_config(true);
// Configure 1 directly reachable subnet, parked-packet-limit of 1.
@@ -3118,3 +3305,4 @@ TEST_F(HooksDhcpv4SrvTest, parkedPacketLimit) {
EXPECT_EQ(1, getStatistic("pkt4-receive-drop"));
}
+} // namespace
diff --git a/src/bin/dhcp4/tests/out_of_range_unittest.cc b/src/bin/dhcp4/tests/out_of_range_unittest.cc
index a11cfe6735..f5769474cb 100644
--- a/src/bin/dhcp4/tests/out_of_range_unittest.cc
+++ b/src/bin/dhcp4/tests/out_of_range_unittest.cc
@@ -106,7 +106,6 @@ const char* OOR_CONFIGS[] = {
"}"
"}",
-
// Configuration 3 - different subnet with reservations
"{ \"interfaces-config\": {"
" \"interfaces\": [ \"*\" ]"
@@ -164,35 +163,35 @@ const char* OOR_CONFIGS[] = {
};
-/// @brief Enum for indexing into the array of configurations.
-/// These were created to make the test cases easier to follow.
-enum CfgIndex {
- REF_CFG = 0,
- DIFF_POOL,
- DIFF_POOL_NO_HR,
- DIFF_SUBNET,
- DIFF_SUBNET_NO_HR,
- NO_HR
-};
-
-/// @brief Enum for specifying expected response to client renewal attempt
-enum RenewOutcome {
- DOES_RENEW,
- DOES_NOT_RENEW,
- DOES_NOT_NAK
-};
-
-/// @brief Enum for specifying expected response to client release attempt
-enum ReleaseOutcome {
- DOES_RELEASE,
- DOES_NOT_RELEASE
-};
-
/// @brief Test fixture class for testing various exchanges when the client's
/// leased address is out of range due to configuration changes.
class OutOfRangeTest : public Dhcpv4SrvTest {
public:
- D2ClientMgr& d2_mgr_;
+
+ /// @brief Enum for indexing into the array of configurations.
+ /// These were created to make the test cases easier to follow.
+ enum CfgIndex {
+ REF_CFG = 0,
+ DIFF_POOL,
+ DIFF_POOL_NO_HR,
+ DIFF_SUBNET,
+ DIFF_SUBNET_NO_HR,
+ NO_HR
+ };
+
+ /// @brief Enum for specifying expected response to client renewal attempt.
+ enum RenewOutcome {
+ DOES_RENEW,
+ DOES_NOT_RENEW,
+ DOES_NOT_NAK
+ };
+
+ /// @brief Enum for specifying expected response to client release attempt.
+ enum ReleaseOutcome {
+ DOES_RELEASE_EXPIRE,
+ DOES_RELEASE_DELETE,
+ DOES_NOT_RELEASE
+ };
/// @brief Constructor.
///
@@ -209,9 +208,18 @@ public:
~OutOfRangeTest() {
}
- void configure(const std::string& config, Dhcp4Client& client) {
+ /// @brief Configure specified DHCP server using JSON string.
+ ///
+ /// @param config String holding server configuration in JSON format.
+ /// @param client Instance of the client.
+ /// @param disable_affinity A boolean flag which indicates if lease affinity
+ /// should be disabled.
+ void configure(const std::string& config, Dhcp4Client& client,
+ const bool disable_affinity = true) {
NakedDhcpv4Srv& server = *client.getServer();
- ASSERT_NO_FATAL_FAILURE(Dhcpv4SrvTest::configure(config, server));
+ ASSERT_NO_FATAL_FAILURE(Dhcpv4SrvTest::configure(config, server, true,
+ true, true, false,
+ disable_affinity));
if (d2_mgr_.ddnsEnabled()) {
ASSERT_NO_THROW(server.startD2());
}
@@ -266,32 +274,39 @@ public:
/// @param renew_outcome - expected server reaction in response to the
/// client's stage two renewal attempt.
/// @param release_outcome - expected server reaction in response to the
- /// client's stage two release attempt. Currently defaults to DOES_RELEASE
+ /// client's stage two release attempt. Currently defaults to DOES_RELEASE_DELETE
/// as no cases have been identified which do otherwise.
- void oorRenewReleaseTest(enum CfgIndex cfg_idx,
+ /// @param disable_affinity A boolean flag which indicates if lease affinity
+ /// should be disabled. In the case lease affinity is enabled, the lease is
+ /// not removed, but instead it is expired, and no DNS update is performed.
+ void oorRenewReleaseTest(CfgIndex cfg_idx,
const std::string& hwaddress,
const std::string& expected_address,
- enum RenewOutcome renew_outcome,
- enum ReleaseOutcome release_outcome = DOES_RELEASE);
+ RenewOutcome renew_outcome,
+ ReleaseOutcome release_outcome = DOES_RELEASE_DELETE,
+ const bool disable_affinity = true);
+
+ /// @brief D2 client manager.
+ D2ClientMgr& d2_mgr_;
/// @brief Interface Manager's fake configuration control.
IfaceMgrTestConfig iface_mgr_test_config_;
-
};
void
-OutOfRangeTest::oorRenewReleaseTest(enum CfgIndex cfg_idx,
- const std::string& hwaddress,
- const std::string& expected_address,
- enum RenewOutcome renew_outcome,
- enum ReleaseOutcome release_outcome) {
+OutOfRangeTest::oorRenewReleaseTest(CfgIndex cfg_idx,
+ const std::string& hwaddress,
+ const std::string& expected_address,
+ RenewOutcome renew_outcome,
+ ReleaseOutcome release_outcome,
+ const bool disable_affinity) {
// STAGE ONE:
// Step 1 is to acquire the lease
Dhcp4Client client(Dhcp4Client::SELECTING);
// Configure DHCP server.
- configure(OOR_CONFIGS[REF_CFG], client);
+ configure(OOR_CONFIGS[REF_CFG], client, disable_affinity);
// Set the host name so DNS updates will be performed
client.includeHostname("test.example.com");
@@ -338,7 +353,7 @@ OutOfRangeTest::oorRenewReleaseTest(enum CfgIndex cfg_idx,
// STAGE TWO:
// Now reconfigure which should render our leased address out-of-range
- configure(OOR_CONFIGS[cfg_idx], client);
+ configure(OOR_CONFIGS[cfg_idx], client, disable_affinity);
// Try to renew after the configuration change..
ASSERT_NO_THROW(client.doRequest());
@@ -372,55 +387,86 @@ OutOfRangeTest::oorRenewReleaseTest(enum CfgIndex cfg_idx,
lease = LeaseMgrFactory::instance().getLease4(leased_address);
- if (release_outcome == DOES_RELEASE) {
+ if (release_outcome == DOES_RELEASE_DELETE) {
EXPECT_FALSE(lease);
// Verify the DNS remove was queued.
verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE,
leased_address.toText());
} else {
// Lease should still exist, and no NCR should be queued.
- EXPECT_TRUE(lease);
+ ASSERT_TRUE(lease);
EXPECT_EQ(0, d2_mgr_.getQueueSize());
+ if (release_outcome == DOES_RELEASE_EXPIRE) {
+ EXPECT_TRUE(lease->expired());
+ } else {
+ EXPECT_FALSE(lease->expired());
+ }
}
}
-
// Verifies that once-valid lease, whose address is no longer
// within the subnet's pool:
//
// a: Is NAKed upon a renewal attempt
-// b: Is released properly upon release, including DNS removal
+// b: Is deleted properly upon release, including DNS removal
//
TEST_F(OutOfRangeTest, dynamicOutOfPool) {
std::string hwaddress = "";
std::string expected_address = "";
- oorRenewReleaseTest(DIFF_POOL, hwaddress, expected_address,
- DOES_NOT_NAK);
+ oorRenewReleaseTest(DIFF_POOL, hwaddress, expected_address, DOES_NOT_NAK);
+}
+
+// Verifies that once-valid lease, whose address is no longer
+// within the subnet's pool:
+//
+// a: Is NAKed upon a renewal attempt
+// b: Is expired properly upon release, including no DNS removal
+//
+TEST_F(OutOfRangeTest, dynamicOutOfPoolNoDelete) {
+
+ std::string hwaddress = "";
+ std::string expected_address = "";
+ oorRenewReleaseTest(DIFF_POOL, hwaddress, expected_address, DOES_NOT_NAK,
+ DOES_RELEASE_EXPIRE, false);
}
// Verifies that once-valid lease whose address is no longer
// within any configured subnet:
//
// a: Is NAKed upon a renewal attempt
-// b: Is released properly upon release, including DNS removal
+// b: Is deleted properly upon release, including DNS removal
//
TEST_F(OutOfRangeTest, dynamicOutOfSubnet) {
std::string hwaddress = "";
std::string expected_address = "";
- oorRenewReleaseTest(DIFF_SUBNET, hwaddress, expected_address,
- DOES_NOT_RENEW);
+ oorRenewReleaseTest(DIFF_SUBNET, hwaddress, expected_address, DOES_NOT_RENEW);
+}
+
+// Verifies that once-valid lease whose address is no longer
+// within any configured subnet:
+//
+// a: Is NAKed upon a renewal attempt
+// b: Is expired properly upon release, including no DNS removal
+//
+TEST_F(OutOfRangeTest, dynamicOutOfSubnetNoDelete) {
+
+ std::string hwaddress = "";
+ std::string expected_address = "";
+
+ oorRenewReleaseTest(DIFF_SUBNET, hwaddress, expected_address, DOES_NOT_RENEW,
+ DOES_RELEASE_EXPIRE, false);
}
// Test verifies that once-valid dynamic address host reservation,
// whose address is no longer within the subnet's pool:
//
// a: Is NAKed upon a renewal attempt
-// b: Is released properly upon release, including DNS removal
+// b: Is deleted properly upon release, including DNS removal
//
TEST_F(OutOfRangeTest, dynamicHostOutOfPool) {
std::string hwaddress = "dd:dd:dd:dd:dd:01";
@@ -430,17 +476,44 @@ TEST_F(OutOfRangeTest, dynamicHostOutOfPool) {
}
// Test verifies that once-valid dynamic address host reservation,
+// whose address is no longer within the subnet's pool:
+//
+// a: Is NAKed upon a renewal attempt
+// b: Is expired properly upon release, including no DNS removal
+//
+TEST_F(OutOfRangeTest, dynamicHostOutOfPoolNoDelete) {
+ std::string hwaddress = "dd:dd:dd:dd:dd:01";
+ std::string expected_address = "";
+
+ oorRenewReleaseTest(DIFF_POOL, hwaddress, expected_address, DOES_NOT_NAK,
+ DOES_RELEASE_EXPIRE, false);
+}
+
+// Test verifies that once-valid dynamic address host reservation,
// whose address is no longer within any configured subnet:
//
// a: Is NAKed upon a renewal attempt
-// b: Is released properly upon release, including DNS removal
+// b: Is deleted properly upon release, including DNS removal
//
TEST_F(OutOfRangeTest, dynamicHostOutOfSubnet) {
std::string hwaddress = "dd:dd:dd:dd:dd:01";
std::string expected_address = "";
- oorRenewReleaseTest(DIFF_SUBNET, hwaddress, expected_address,
- DOES_NOT_RENEW);
+ oorRenewReleaseTest(DIFF_SUBNET, hwaddress, expected_address, DOES_NOT_RENEW);
+}
+
+// Test verifies that once-valid dynamic address host reservation,
+// whose address is no longer within any configured subnet:
+//
+// a: Is NAKed upon a renewal attempt
+// b: Is expired properly upon release, including no DNS removal
+//
+TEST_F(OutOfRangeTest, dynamicHostOutOfSubnetNoDelete) {
+ std::string hwaddress = "dd:dd:dd:dd:dd:01";
+ std::string expected_address = "";
+
+ oorRenewReleaseTest(DIFF_SUBNET, hwaddress, expected_address, DOES_NOT_RENEW,
+ DOES_RELEASE_EXPIRE, false);
}
// Test verifies that once-valid dynamic address host reservation,
@@ -448,7 +521,7 @@ TEST_F(OutOfRangeTest, dynamicHostOutOfSubnet) {
// reservation has been removed:
//
// a: Is allowed to renew
-// b: Is released properly upon release, including DNS removal
+// b: Is deleted properly upon release, including DNS removal
//
TEST_F(OutOfRangeTest, dynamicHostReservationRemoved) {
Dhcp4Client client(Dhcp4Client::SELECTING);
@@ -460,11 +533,28 @@ TEST_F(OutOfRangeTest, dynamicHostReservationRemoved) {
}
// Test verifies that once-valid dynamic address host reservation,
+// whose address is within the configured subnet and pool, but whose
+// reservation has been removed:
+//
+// a: Is allowed to renew
+// b: Is expired properly upon release, including no DNS removal
+//
+TEST_F(OutOfRangeTest, dynamicHostReservationRemovedNoDelete) {
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+
+ std::string hwaddress = "dd:dd:dd:dd:dd:01";
+ std::string expected_address = "";
+
+ oorRenewReleaseTest(NO_HR, hwaddress, expected_address, DOES_RENEW,
+ DOES_RELEASE_EXPIRE, false);
+}
+
+// Test verifies that once-valid dynamic address host reservation,
// whose address is no longer within any configured subnet, and which
// no longer has reservation defined:
//
// a: Is NAKed upon a renewal attempt
-// b: Is released properly upon release, including DNS removal
+// b: Is deleted properly upon release, including DNS removal
//
TEST_F(OutOfRangeTest, dynamicHostOutOfSubnetReservationRemoved) {
Dhcp4Client client(Dhcp4Client::SELECTING);
@@ -472,30 +562,58 @@ TEST_F(OutOfRangeTest, dynamicHostOutOfSubnetReservationRemoved) {
std::string hwaddress = "dd:dd:dd:dd:dd:01";
std::string expected_address = "";
- oorRenewReleaseTest(DIFF_SUBNET_NO_HR, hwaddress, expected_address,
- DOES_NOT_RENEW);
+ oorRenewReleaseTest(DIFF_SUBNET_NO_HR, hwaddress, expected_address, DOES_NOT_RENEW);
+}
+
+// Test verifies that once-valid dynamic address host reservation,
+// whose address is no longer within any configured subnet, and which
+// no longer has reservation defined:
+//
+// a: Is NAKed upon a renewal attempt
+// b: Is expired properly upon release, including no DNS removal
+//
+TEST_F(OutOfRangeTest, dynamicHostOutOfSubnetReservationRemovedNoDelete) {
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+
+ std::string hwaddress = "dd:dd:dd:dd:dd:01";
+ std::string expected_address = "";
+
+ oorRenewReleaseTest(DIFF_SUBNET_NO_HR, hwaddress, expected_address, DOES_NOT_RENEW,
+ DOES_RELEASE_EXPIRE, false);
}
// Test verifies that once-valid in-subnet fixed-address host reservation,
// after the subnet pool changes:
//
// a: Is NAK'd upon a renewal attempt
-// b: Is released properly upon release, including DNS removal
+// b: Is deleted properly upon release, including DNS removal
//
TEST_F(OutOfRangeTest, fixedHostOutOfSubnet) {
std::string hwaddress = "ff:ff:ff:ff:ff:01";
std::string expected_address = "10.0.0.7";
- oorRenewReleaseTest(DIFF_SUBNET, hwaddress, expected_address,
- DOES_NOT_RENEW);
+ oorRenewReleaseTest(DIFF_SUBNET, hwaddress, expected_address, DOES_NOT_RENEW);
}
+// Test verifies that once-valid in-subnet fixed-address host reservation,
+// after the subnet pool changes:
+//
+// a: Is NAK'd upon a renewal attempt
+// b: Is expired properly upon release, including no DNS removal
+//
+TEST_F(OutOfRangeTest, fixedHostOutOfSubnetNoDelete) {
+ std::string hwaddress = "ff:ff:ff:ff:ff:01";
+ std::string expected_address = "10.0.0.7";
+
+ oorRenewReleaseTest(DIFF_SUBNET, hwaddress, expected_address, DOES_NOT_RENEW,
+ DOES_RELEASE_EXPIRE, false);
+}
// Test verifies that once-valid in-subnet fixed-address host reservation,
// after the subnet pool is changed:
//
// a: Is ACK'd upon a renewal attempt
-// b: Is released properly upon release, including DNS removal
+// b: Is deleted properly upon release, including DNS removal
//
TEST_F(OutOfRangeTest, fixedHostDifferentPool) {
std::string hwaddress = "ff:ff:ff:ff:ff:01";
@@ -505,10 +623,24 @@ TEST_F(OutOfRangeTest, fixedHostDifferentPool) {
}
// Test verifies that once-valid in-subnet fixed-address host reservation,
+// after the subnet pool is changed:
+//
+// a: Is ACK'd upon a renewal attempt
+// b: Is expired properly upon release, including no DNS removal
+//
+TEST_F(OutOfRangeTest, fixedHostDifferentPoolNoDelete) {
+ std::string hwaddress = "ff:ff:ff:ff:ff:01";
+ std::string expected_address = "10.0.0.7";
+
+ oorRenewReleaseTest(DIFF_POOL, hwaddress, expected_address, DOES_RENEW,
+ DOES_RELEASE_EXPIRE, false);
+}
+
+// Test verifies that once-valid in-subnet fixed-address host reservation,
// whose reservation has been removed from the configuration
//
// a: Is NAK'd upon a renewal attempt
-// b: Is released properly upon release, including DNS removal
+// b: Is deleted properly upon release, including DNS removal
//
TEST_F(OutOfRangeTest, fixedHostReservationRemoved) {
std::string hwaddress = "ff:ff:ff:ff:ff:01";
@@ -517,18 +649,46 @@ TEST_F(OutOfRangeTest, fixedHostReservationRemoved) {
oorRenewReleaseTest(NO_HR, hwaddress, expected_address, DOES_NOT_NAK);
}
+
+// Test verifies that once-valid in-subnet fixed-address host reservation,
+// whose reservation has been removed from the configuration
+//
+// a: Is NAK'd upon a renewal attempt
+// b: Is expired properly upon release, including no DNS removal
+//
+TEST_F(OutOfRangeTest, fixedHostReservationRemovedNoDelete) {
+ std::string hwaddress = "ff:ff:ff:ff:ff:01";
+ std::string expected_address = "10.0.0.7";
+
+ oorRenewReleaseTest(NO_HR, hwaddress, expected_address, DOES_NOT_NAK,
+ DOES_RELEASE_EXPIRE, false);
+}
+
// Test verifies that once-valid fixed address host reservation,
// whose address is no longer within any configured subnet
//
// a: Is NAKed upon a renewal attempt
-// b: Is released properly upon release, including DNS removal
+// b: Is deleted properly upon release, including DNS removal
//
TEST_F(OutOfRangeTest, fixedHostOutOfSubnetReservationRemoved) {
std::string hwaddress = "ff:ff:ff:ff:ff:01";
std::string expected_address = "10.0.0.7";
- oorRenewReleaseTest(DIFF_SUBNET_NO_HR, hwaddress, expected_address,
- DOES_NOT_RENEW);
+ oorRenewReleaseTest(DIFF_SUBNET_NO_HR, hwaddress, expected_address, DOES_NOT_RENEW);
+}
+
+// Test verifies that once-valid fixed address host reservation,
+// whose address is no longer within any configured subnet
+//
+// a: Is NAKed upon a renewal attempt
+// b: Is expired properly upon release, including no DNS removal
+//
+TEST_F(OutOfRangeTest, fixedHostOutOfSubnetReservationRemovedNoDelete) {
+ std::string hwaddress = "ff:ff:ff:ff:ff:01";
+ std::string expected_address = "10.0.0.7";
+
+ oorRenewReleaseTest(DIFF_SUBNET_NO_HR, hwaddress, expected_address, DOES_NOT_RENEW,
+ DOES_RELEASE_EXPIRE, false);
}
} // end of anonymous namespace
diff --git a/src/bin/dhcp4/tests/release_unittest.cc b/src/bin/dhcp4/tests/release_unittest.cc
index f2f66f32cf..cff11d5ec3 100644
--- a/src/bin/dhcp4/tests/release_unittest.cc
+++ b/src/bin/dhcp4/tests/release_unittest.cc
@@ -61,7 +61,8 @@ class ReleaseTest : public Dhcpv4SrvTest {
public:
enum ExpectedResult {
- SHOULD_PASS,
+ SHOULD_PASS_EXPIRED,
+ SHOULD_PASS_DELETED,
SHOULD_FAIL
};
@@ -69,8 +70,7 @@ public:
///
/// Sets up fake interfaces.
ReleaseTest()
- : Dhcpv4SrvTest(),
- iface_mgr_test_config_(true) {
+ : Dhcpv4SrvTest(), iface_mgr_test_config_(true) {
}
/// @brief Performs 4-way exchange to obtain new lease.
@@ -84,18 +84,21 @@ public:
/// @param client_id_1 Client id to be used to acquire the lease.
/// @param hw_address_2 HW Address to be used to release the lease.
/// @param client_id_2 Client id to be used to release the lease.
- /// @param expected_result SHOULD_PASS if the lease is expected to
- /// be successfully released, or SHOULD_FAIL if the lease is expected
- /// to not be released.
+ /// @param expected_result SHOULD_PASS_EXPIRED if the lease is expected to
+ /// be successfully released and expired, SHOULD_PASS_DELETED if the lease
+ /// is expected to be successfully released and deleted, or SHOULD_FAIL if
+ /// the lease is expected to not be released.
+ /// @param disable_affinity A boolean flag which indicates if lease affinity
+ /// should be disabled.
void acquireAndRelease(const std::string& hw_address_1,
const std::string& client_id_1,
const std::string& hw_address_2,
const std::string& client_id_2,
- ExpectedResult expected_result);
+ ExpectedResult expected_result,
+ const bool disable_affinity = true);
/// @brief Interface Manager's fake configuration control.
IfaceMgrTestConfig iface_mgr_test_config_;
-
};
void
@@ -123,11 +126,12 @@ ReleaseTest::acquireAndRelease(const std::string& hw_address_1,
const std::string& client_id_1,
const std::string& hw_address_2,
const std::string& client_id_2,
- ExpectedResult expected_result) {
+ ExpectedResult expected_result,
+ const bool disable_affinity) {
CfgMgr::instance().clear();
Dhcp4Client client(Dhcp4Client::SELECTING);
// Configure DHCP server.
- configure(RELEASE_CONFIGS[0], *client.getServer());
+ configure(RELEASE_CONFIGS[0], *client.getServer(), true, true, true, false, disable_affinity);
// Explicitly set the client id.
client.includeClientId(client_id_1);
// Explicitly set the HW address.
@@ -167,7 +171,16 @@ ReleaseTest::acquireAndRelease(const std::string& hw_address_1,
// We check if the release process was successful by checking if the
// lease is in the database. It is expected that it is not present,
// i.e. has been deleted with the release.
- if (expected_result == SHOULD_PASS) {
+ if (expected_result == SHOULD_PASS_EXPIRED) {
+ ASSERT_TRUE(lease);
+
+ // The update succeeded, so the assigned-address should be expired
+ EXPECT_TRUE(lease->expired());
+
+ // No lease has been removed, so the assigned-address should be the same
+ // as before
+ EXPECT_EQ(before, after);
+ } else if (expected_result == SHOULD_PASS_DELETED) {
EXPECT_FALSE(lease);
// The removal succeeded, so the assigned-addresses statistic should
@@ -186,7 +199,14 @@ ReleaseTest::acquireAndRelease(const std::string& hw_address_1,
TEST_F(ReleaseTest, releaseNoIdentifierChange) {
acquireAndRelease("01:02:03:04:05:06", "12:14",
"01:02:03:04:05:06", "12:14",
- SHOULD_PASS);
+ SHOULD_PASS_DELETED);
+}
+
+// This test checks that the client can acquire and release the lease.
+TEST_F(ReleaseTest, releaseNoDeleteNoIdentifierChange) {
+ acquireAndRelease("01:02:03:04:05:06", "12:14",
+ "01:02:03:04:05:06", "12:14",
+ SHOULD_PASS_EXPIRED, false);
}
// This test verifies the release correctness in the following case:
@@ -197,7 +217,18 @@ TEST_F(ReleaseTest, releaseNoIdentifierChange) {
TEST_F(ReleaseTest, releaseHWAddressOnly) {
acquireAndRelease("01:02:03:04:05:06", "",
"01:02:03:04:05:06", "",
- SHOULD_PASS);
+ SHOULD_PASS_DELETED);
+}
+
+// This test verifies the release correctness in the following case:
+// - Client acquires new lease using HW address only
+// - Client sends the DHCPRELEASE with valid HW address and without
+// client identifier.
+// - The server successfully releases the lease.
+TEST_F(ReleaseTest, releaseNoDeleteHWAddressOnly) {
+ acquireAndRelease("01:02:03:04:05:06", "",
+ "01:02:03:04:05:06", "",
+ SHOULD_PASS_EXPIRED, false);
}
// This test verifies the release correctness in the following case:
@@ -208,7 +239,18 @@ TEST_F(ReleaseTest, releaseHWAddressOnly) {
TEST_F(ReleaseTest, releaseNoClientId) {
acquireAndRelease("01:02:03:04:05:06", "12:14",
"01:02:03:04:05:06", "",
- SHOULD_PASS);
+ SHOULD_PASS_DELETED);
+}
+
+// This test verifies the release correctness in the following case:
+// - Client acquires new lease using the client identifier and HW address
+// - Client sends the DHCPRELEASE with valid HW address but with no
+// client identifier.
+// - The server successfully releases the lease.
+TEST_F(ReleaseTest, releaseNoDeleteNoClientId) {
+ acquireAndRelease("01:02:03:04:05:06", "12:14",
+ "01:02:03:04:05:06", "",
+ SHOULD_PASS_EXPIRED, false);
}
// This test verifies the release correctness in the following case:
@@ -220,7 +262,19 @@ TEST_F(ReleaseTest, releaseNoClientId) {
TEST_F(ReleaseTest, releaseNoClientId2) {
acquireAndRelease("01:02:03:04:05:06", "",
"01:02:03:04:05:06", "12:14",
- SHOULD_PASS);
+ SHOULD_PASS_DELETED);
+}
+
+// This test verifies the release correctness in the following case:
+// - Client acquires new lease using HW address
+// - Client sends the DHCPRELEASE with valid HW address and some
+// client identifier.
+// - The server identifies the lease using HW address and releases
+// this lease.
+TEST_F(ReleaseTest, releaseNoDeleteNoClientId2) {
+ acquireAndRelease("01:02:03:04:05:06", "",
+ "01:02:03:04:05:06", "12:14",
+ SHOULD_PASS_EXPIRED, false);
}
// This test checks the server's behavior in the following case:
@@ -243,7 +297,19 @@ TEST_F(ReleaseTest, releaseNonMatchingClientId) {
TEST_F(ReleaseTest, releaseNonMatchingHWAddress) {
acquireAndRelease("01:02:03:04:05:06", "12:14",
"06:06:06:06:06:06", "12:14",
- SHOULD_PASS);
+ SHOULD_PASS_DELETED);
+}
+
+// This test checks the server's behavior in the following case:
+// - Client acquires new lease using client identifier and HW address
+// - Client sends the DHCPRELEASE with the same client identifier but
+// different HW address.
+// - The server uses client identifier to find the client's lease and
+// releases it.
+TEST_F(ReleaseTest, releaseNoDeleteNonMatchingHWAddress) {
+ acquireAndRelease("01:02:03:04:05:06", "12:14",
+ "06:06:06:06:06:06", "12:14",
+ SHOULD_PASS_EXPIRED, false);
}
// This test checks the server's behavior in the following case:
@@ -273,6 +339,33 @@ TEST_F(ReleaseTest, releaseNonMatchingIPAddress) {
ASSERT_TRUE(lease);
}
+// This test checks the server's behavior in the following case:
+// - Client acquires new lease.
+// - Client sends DHCPRELEASE with the ciaddr set to a different
+// address than it has acquired from the server.
+// - Server determines that the client is trying to release a
+// wrong address and will refuse to release.
+TEST_F(ReleaseTest, releaseNoDeleteNonMatchingIPAddress) {
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ // Configure DHCP server.
+ configure(RELEASE_CONFIGS[0], *client.getServer(), true, true, true, false, false);
+ // Perform 4-way exchange to obtain a new lease.
+ acquireLease(client);
+
+ // Remember the acquired address.
+ IOAddress leased_address = client.config_.lease_.addr_;
+
+ // Modify the client's address to force it to release a different address
+ // than it has obtained from the server.
+ client.config_.lease_.addr_ = IOAddress(leased_address.toUint32() + 1);
+
+ // Send DHCPRELEASE and make sure it was unsuccessful, i.e. the lease
+ // remains in the database.
+ ASSERT_NO_THROW(client.doRelease());
+ Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(leased_address);
+ ASSERT_TRUE(lease);
+}
+
// This test verifies that an incoming RELEASE for an address within
// a subnet that has been removed can still be released.
TEST_F(ReleaseTest, releaseNoSubnet) {
@@ -296,4 +389,30 @@ TEST_F(ReleaseTest, releaseNoSubnet) {
EXPECT_FALSE(lease);
}
+// This test verifies that an incoming RELEASE for an address within
+// a subnet that has been removed can still be released.
+TEST_F(ReleaseTest, releaseNoDeleteNoSubnet) {
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ // Configure DHCP server.
+ configure(RELEASE_CONFIGS[0], *client.getServer(), true, true, true, false, false);
+ // Perform 4-way exchange to obtain a new lease.
+ acquireLease(client);
+
+ // Remember the acquired address.
+ IOAddress leased_address = client.config_.lease_.addr_;
+
+ // Release is as it was relayed
+ client.useRelay(true);
+
+ // Send the release
+ ASSERT_NO_THROW(client.doRelease());
+
+ // Check that the lease was not removed
+ Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(leased_address);
+ ASSERT_TRUE(lease);
+
+ // Check That the lease has been expired
+ EXPECT_TRUE(lease->expired());
+}
+
} // end of anonymous namespace
diff --git a/src/bin/dhcp4/tests/shared_network_unittest.cc b/src/bin/dhcp4/tests/shared_network_unittest.cc
index f9c137c858..10afcc2b14 100644
--- a/src/bin/dhcp4/tests/shared_network_unittest.cc
+++ b/src/bin/dhcp4/tests/shared_network_unittest.cc
@@ -2122,7 +2122,7 @@ TEST_F(Dhcpv4SharedNetworkTest, matchClientId) {
// Shared network is selected based on the client class specified.
TEST_F(Dhcpv4SharedNetworkTest, sharedNetworkSelectedByClass) {
- // Create client #1.
+ // Create client #1.
Dhcp4Client client1(Dhcp4Client::SELECTING);
client1.setIfaceName("eth1");
client1.setIfaceIndex(ETH1_INDEX);
diff --git a/src/bin/dhcp6/dhcp6_messages.cc b/src/bin/dhcp6/dhcp6_messages.cc
index 4249c7f6e1..b93c162c7c 100644
--- a/src/bin/dhcp6/dhcp6_messages.cc
+++ b/src/bin/dhcp6/dhcp6_messages.cc
@@ -136,10 +136,14 @@ extern const isc::log::MessageID DHCP6_QUERY_DATA = "DHCP6_QUERY_DATA";
extern const isc::log::MessageID DHCP6_RAPID_COMMIT = "DHCP6_RAPID_COMMIT";
extern const isc::log::MessageID DHCP6_RECLAIM_EXPIRED_LEASES_FAIL = "DHCP6_RECLAIM_EXPIRED_LEASES_FAIL";
extern const isc::log::MessageID DHCP6_RELEASE_NA = "DHCP6_RELEASE_NA";
+extern const isc::log::MessageID DHCP6_RELEASE_NA_DELETED = "DHCP6_RELEASE_NA_DELETED";
+extern const isc::log::MessageID DHCP6_RELEASE_NA_EXPIRED = "DHCP6_RELEASE_NA_EXPIRED";
extern const isc::log::MessageID DHCP6_RELEASE_NA_FAIL = "DHCP6_RELEASE_NA_FAIL";
extern const isc::log::MessageID DHCP6_RELEASE_NA_FAIL_WRONG_DUID = "DHCP6_RELEASE_NA_FAIL_WRONG_DUID";
extern const isc::log::MessageID DHCP6_RELEASE_NA_FAIL_WRONG_IAID = "DHCP6_RELEASE_NA_FAIL_WRONG_IAID";
extern const isc::log::MessageID DHCP6_RELEASE_PD = "DHCP6_RELEASE_PD";
+extern const isc::log::MessageID DHCP6_RELEASE_PD_DELETED = "DHCP6_RELEASE_PD_DELETED";
+extern const isc::log::MessageID DHCP6_RELEASE_PD_EXPIRED = "DHCP6_RELEASE_PD_EXPIRED";
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL = "DHCP6_RELEASE_PD_FAIL";
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_DUID = "DHCP6_RELEASE_PD_FAIL_WRONG_DUID";
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_IAID = "DHCP6_RELEASE_PD_FAIL_WRONG_IAID";
@@ -299,10 +303,14 @@ const char* values[] = {
"DHCP6_RAPID_COMMIT", "%1: Rapid Commit option received, following 2-way exchange",
"DHCP6_RECLAIM_EXPIRED_LEASES_FAIL", "failed to reclaim expired leases: %1",
"DHCP6_RELEASE_NA", "%1: binding for address %2 and iaid=%3 was released properly",
+ "DHCP6_RELEASE_NA_DELETED", "%1: binding for address %2 and iaid=%3 was properly deleted on release",
+ "DHCP6_RELEASE_NA_EXPIRED", "%1: binding for address %2 and iaid=%3 was properly expired on release",
"DHCP6_RELEASE_NA_FAIL", "%1: failed to remove address lease for address %2 and iaid=%3",
"DHCP6_RELEASE_NA_FAIL_WRONG_DUID", "%1: client tried to release address %2, but it belongs to another client using duid=%3",
"DHCP6_RELEASE_NA_FAIL_WRONG_IAID", "%1: client tried to release address %2, but it used wrong IAID (expected %3, but got %4)",
"DHCP6_RELEASE_PD", "%1: prefix %2/%3 for iaid=%4 was released properly",
+ "DHCP6_RELEASE_PD_DELETED", "%1: prefix %2/%3 for iaid=%4 was properly deleted on release",
+ "DHCP6_RELEASE_PD_EXPIRED", "%1: prefix %2/%3 for iaid=%4 was properly expired on release",
"DHCP6_RELEASE_PD_FAIL", "%1: failed to release prefix %2/%3 for iaid=%4",
"DHCP6_RELEASE_PD_FAIL_WRONG_DUID", "%1: client tried to release prefix %2/%3, but it belongs to another client (duid=%4)",
"DHCP6_RELEASE_PD_FAIL_WRONG_IAID", "%1: client tried to release prefix %2/%3, but it used wrong IAID (expected %4, but got %5)",
diff --git a/src/bin/dhcp6/dhcp6_messages.h b/src/bin/dhcp6/dhcp6_messages.h
index 7e88e99a5b..5ec8aa1eed 100644
--- a/src/bin/dhcp6/dhcp6_messages.h
+++ b/src/bin/dhcp6/dhcp6_messages.h
@@ -137,10 +137,14 @@ extern const isc::log::MessageID DHCP6_QUERY_DATA;
extern const isc::log::MessageID DHCP6_RAPID_COMMIT;
extern const isc::log::MessageID DHCP6_RECLAIM_EXPIRED_LEASES_FAIL;
extern const isc::log::MessageID DHCP6_RELEASE_NA;
+extern const isc::log::MessageID DHCP6_RELEASE_NA_DELETED;
+extern const isc::log::MessageID DHCP6_RELEASE_NA_EXPIRED;
extern const isc::log::MessageID DHCP6_RELEASE_NA_FAIL;
extern const isc::log::MessageID DHCP6_RELEASE_NA_FAIL_WRONG_DUID;
extern const isc::log::MessageID DHCP6_RELEASE_NA_FAIL_WRONG_IAID;
extern const isc::log::MessageID DHCP6_RELEASE_PD;
+extern const isc::log::MessageID DHCP6_RELEASE_PD_DELETED;
+extern const isc::log::MessageID DHCP6_RELEASE_PD_EXPIRED;
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL;
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_DUID;
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_IAID;
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index 049c61e161..470e2c1660 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -795,7 +795,21 @@ and provides the cause of failure.
% DHCP6_RELEASE_NA %1: binding for address %2 and iaid=%3 was released properly
This informational message indicates that an address was released properly. It
-is a normal operation during client shutdown.
+is a normal operation during client shutdown. The first argument includes
+the client and transaction identification information. The second and third
+argument hold the released IPv6 address and IAID respectively.
+
+% DHCP6_RELEASE_NA_EXPIRED %1: binding for address %2 and iaid=%3 was properly expired on release
+This informational message indicates that an address was properly expired on
+release. It is a normal operation during client shutdown. The first argument
+includes the client and transaction identification information. The second and
+third argument hold the released IPv6 address and IAID respectively.
+
+% DHCP6_RELEASE_NA_DELETED %1: binding for address %2 and iaid=%3 was properly deleted on release
+This informational message indicates that an address was properly deleted on
+release. It is a normal operation during client shutdown. The first argument
+includes the client and transaction identification information. The second and
+third argument hold the released IPv6 address and IAID respectively.
% DHCP6_RELEASE_NA_FAIL %1: failed to remove address lease for address %2 and iaid=%3
This error message indicates that the software failed to remove an address
@@ -825,8 +839,19 @@ support for multiple addresses is flawed.
This informational message indicates that a prefix was released properly. It
is a normal operation during client shutdown. The first argument holds
the client and transaction identification information. The second and
-third argument define the prefix and its length. The fourth argument
-holds IAID.
+third argument hold the prefix and its length. The fourth argument holds IAID.
+
+% DHCP6_RELEASE_PD_EXPIRED %1: prefix %2/%3 for iaid=%4 was properly expired on release
+This informational message indicates that a prefix was properly expired on
+release. It is a normal operation during client shutdown. The first argument
+holds the client and transaction identification information. The second and
+third argument hold the prefix and its length. The fourth argument holds IAID.
+
+% DHCP6_RELEASE_PD_DELETED %1: prefix %2/%3 for iaid=%4 was properly deleted on release
+This informational message indicates that a prefix was properly deleted on
+release. It is a normal operation during client shutdown. The first argument
+holds the client and transaction identification information. The second and
+third argument hold the prefix and its length. The fourth argument holds IAID.
% DHCP6_RELEASE_PD_FAIL %1: failed to release prefix %2/%3 for iaid=%4
This error message indicates that the software failed to remove a prefix
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index dfad23ba04..31bb3a7251 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -3127,9 +3127,23 @@ Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
// Ok, we've passed all checks. Let's release this address.
bool success = false; // was the removal operation successful?
+ bool expired = false; // explicitly expired instead of removed?
+ auto expiration_cfg = CfgMgr::instance().getCurrentCfg()->getCfgExpiration();
+ // Callout didn't indicate to skip the release process. Let's release
+ // the address.
if (!skip) {
- success = LeaseMgrFactory::instance().deleteLease(lease);
+ // Delete lease only if affinity is disabled.
+ if (expiration_cfg->getFlushReclaimedTimerWaitTime() &&
+ expiration_cfg->getHoldReclaimedTime()) {
+ // Expire the lease.
+ lease->cltt_ -= lease->valid_lft_ + 1;
+ LeaseMgrFactory::instance().updateLease6(lease);
+ expired = true;
+ success = true;
+ } else {
+ success = LeaseMgrFactory::instance().deleteLease(lease);
+ }
}
// Here the success should be true if we removed lease successfully
@@ -3157,15 +3171,27 @@ Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_Success,
"Lease released. Thank you, please come again."));
- // Need to decrease statistic for assigned addresses.
- StatsMgr::instance().addValue(
- StatsMgr::generateName("subnet", lease->subnet_id_, "assigned-nas"),
- static_cast<int64_t>(-1));
+ if (expired) {
+ LOG_INFO(lease6_logger, DHCP6_RELEASE_NA_EXPIRED)
+ .arg(query->getLabel())
+ .arg(lease->addr_.toText())
+ .arg(lease->iaid_);
+ } else {
+ LOG_INFO(lease6_logger, DHCP6_RELEASE_NA_DELETED)
+ .arg(query->getLabel())
+ .arg(lease->addr_.toText())
+ .arg(lease->iaid_);
+
+ // Need to decrease statistic for assigned addresses.
+ StatsMgr::instance().addValue(
+ StatsMgr::generateName("subnet", lease->subnet_id_, "assigned-nas"),
+ static_cast<int64_t>(-1));
- // Check if a lease has flags indicating that the FQDN update has
- // been performed. If so, create NameChangeRequest which removes
- // the entries.
- queueNCR(CHG_REMOVE, lease);
+ // Check if a lease has flags indicating that the FQDN update has
+ // been performed. If so, create NameChangeRequest which removes
+ // the entries.
+ queueNCR(CHG_REMOVE, lease);
+ }
return (ia_rsp);
}
@@ -3280,20 +3306,36 @@ Dhcpv6Srv::releaseIA_PD(const DuidPtr& duid, const Pkt6Ptr& query,
// Call all installed callouts
HooksManager::callCallouts(Hooks.hook_index_lease6_release_, *callout_handle);
- skip = callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP;
+ // Callouts decided to skip the next processing step. The next
+ // processing step would to send the packet, so skip at this
+ // stage means "drop response".
+ if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
+ (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
+ skip = true;
+ LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_LEASE6_RELEASE_PD_SKIP)
+ .arg(query->getLabel());
+ }
}
// Ok, we've passed all checks. Let's release this prefix.
bool success = false; // was the removal operation successful?
+ bool expired = false; // explicitly expired instead of removed?
+ auto expiration_cfg = CfgMgr::instance().getCurrentCfg()->getCfgExpiration();
+ // Callout didn't indicate to skip the release process. Let's release
+ // the prefix.
if (!skip) {
- success = LeaseMgrFactory::instance().deleteLease(lease);
- } else {
- // Callouts decided to skip the next processing step. The next
- // processing step would to send the packet, so skip at this
- // stage means "drop response".
- LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_LEASE6_RELEASE_PD_SKIP)
- .arg(query->getLabel());
+ // Delete lease only if affinity is disabled.
+ if (expiration_cfg->getFlushReclaimedTimerWaitTime() &&
+ expiration_cfg->getHoldReclaimedTime()) {
+ // Expire the lease.
+ lease->cltt_ -= lease->valid_lft_ + 1;
+ LeaseMgrFactory::instance().updateLease6(lease);
+ expired = true;
+ success = true;
+ } else {
+ success = LeaseMgrFactory::instance().deleteLease(lease);
+ }
}
// Here the success should be true if we removed lease successfully
@@ -3322,10 +3364,24 @@ Dhcpv6Srv::releaseIA_PD(const DuidPtr& duid, const Pkt6Ptr& query,
ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_Success,
"Lease released. Thank you, please come again."));
- // Need to decrease statistic for assigned prefixes.
- StatsMgr::instance().addValue(
- StatsMgr::generateName("subnet", lease->subnet_id_, "assigned-pds"),
- static_cast<int64_t>(-1));
+ if (expired) {
+ LOG_INFO(lease6_logger, DHCP6_RELEASE_PD_EXPIRED)
+ .arg(query->getLabel())
+ .arg(lease->addr_.toText())
+ .arg(static_cast<int>(lease->prefixlen_))
+ .arg(lease->iaid_);
+ } else {
+ LOG_INFO(lease6_logger, DHCP6_RELEASE_PD_DELETED)
+ .arg(query->getLabel())
+ .arg(lease->addr_.toText())
+ .arg(static_cast<int>(lease->prefixlen_))
+ .arg(lease->iaid_);
+
+ // Need to decrease statistic for assigned prefixes.
+ StatsMgr::instance().addValue(
+ StatsMgr::generateName("subnet", lease->subnet_id_, "assigned-pds"),
+ static_cast<int64_t>(-1));
+ }
}
return (ia_rsp);
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index a3620d5cbb..2a3d71b94a 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -2020,10 +2020,28 @@ TEST_F(Dhcpv6SrvTest, pdRenewCache) {
// - lease is actually removed from LeaseMgr
// - assigned-nas stats counter is properly decremented
TEST_F(Dhcpv6SrvTest, ReleaseBasic) {
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setFlushReclaimedTimerWaitTime(0);
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setHoldReclaimedTime(0);
+
testReleaseBasic(Lease::TYPE_NA, IOAddress("2001:db8:1:1::cafe:babe"),
IOAddress("2001:db8:1:1::cafe:babe"));
}
+// This test verifies that incoming (positive) RELEASE with address can be
+// handled properly, that a REPLY is generated, that the response has status
+// code and that the lease is expired and not removed from the database.
+//
+// expected:
+// - returned REPLY message has copy of client-id
+// - returned REPLY message has server-id
+// - returned REPLY message has IA_NA that does not include an IAADDR
+// - lease is actually expired instead of being removed from LeaseMgr
+// - assigned-nas stats counter is unchanged
+TEST_F(Dhcpv6SrvTest, ReleaseBasicNoDelete) {
+ testReleaseBasic(Lease::TYPE_NA, IOAddress("2001:db8:1:1::cafe:babe"),
+ IOAddress("2001:db8:1:1::cafe:babe"), false);
+}
+
// This test verifies that incoming (positive) RELEASE with prefix can be
// handled properly, that a REPLY is generated, that the response has
// status code and that the lease is indeed removed from the database.
@@ -2035,10 +2053,28 @@ TEST_F(Dhcpv6SrvTest, ReleaseBasic) {
// - lease is actually removed from LeaseMgr
// - assigned-pds stats counter is properly decremented
TEST_F(Dhcpv6SrvTest, pdReleaseBasic) {
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setFlushReclaimedTimerWaitTime(0);
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setHoldReclaimedTime(0);
+
testReleaseBasic(Lease::TYPE_PD, IOAddress("2001:db8:1:2::"),
IOAddress("2001:db8:1:2::"));
}
+// This test verifies that incoming (positive) RELEASE with prefix can be
+// handled properly, that a REPLY is generated, that the response has
+// status code and that the lease is expired and not removed from the database.
+//
+// expected:
+// - returned REPLY message has copy of client-id
+// - returned REPLY message has server-id
+// - returned REPLY message has IA_PD that does not include an IAPREFIX
+// - lease is actually expired instead of being removed from LeaseMgr
+// - assigned-pds stats counter is unchanged
+TEST_F(Dhcpv6SrvTest, pdReleaseBasicNoDelete) {
+ testReleaseBasic(Lease::TYPE_PD, IOAddress("2001:db8:1:2::"),
+ IOAddress("2001:db8:1:2::"), false);
+}
+
// This test verifies that incoming (invalid) RELEASE with an address
// can be handled properly.
//
diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.cc b/src/bin/dhcp6/tests/dhcp6_test_utils.cc
index 4d0e79dcb8..d9c6e34df6 100644
--- a/src/bin/dhcp6/tests/dhcp6_test_utils.cc
+++ b/src/bin/dhcp6/tests/dhcp6_test_utils.cc
@@ -558,7 +558,8 @@ Dhcpv6SrvTest::testRenewSomeoneElsesLease(Lease::Type type, const IOAddress& add
void
Dhcpv6SrvTest::testReleaseBasic(Lease::Type type, const IOAddress& existing,
- const IOAddress& release_addr) {
+ const IOAddress& release_addr,
+ const bool disable_affinity) {
NakedDhcpv6Srv srv(0);
const uint32_t iaid = 234;
@@ -597,6 +598,10 @@ Dhcpv6SrvTest::testReleaseBasic(Lease::Type type, const IOAddress& existing,
"assigned-pds");
StatsMgr::instance().setValue(name, static_cast<int64_t>(1));
+ ObservationPtr stat = StatsMgr::instance().getObservation(name);
+ ASSERT_TRUE(stat);
+ uint64_t before = stat->getInteger().first;
+
// Let's create a RELEASE
Pkt6Ptr rel = createMessage(DHCPV6_RELEASE, type, release_addr, prefix_len,
iaid);
@@ -626,20 +631,41 @@ Dhcpv6SrvTest::testReleaseBasic(Lease::Type type, const IOAddress& existing,
checkServerId(reply, srv.getServerID());
checkClientId(reply, clientid);
- // Check that the lease is really gone in the database
- // get lease by address
- l = LeaseMgrFactory::instance().getLease6(type, release_addr);
- ASSERT_FALSE(l);
+ if (disable_affinity) {
+ // Check that the lease is really gone in the database
+ // get lease by address
+ l = LeaseMgrFactory::instance().getLease6(type, release_addr);
+ ASSERT_FALSE(l);
+
+ // get lease by subnetid/duid/iaid combination
+ l = LeaseMgrFactory::instance().getLease6(type, *duid_, iaid,
+ subnet_->getID());
+ ASSERT_FALSE(l);
+
+ // We should have decremented the address counter
+ stat = StatsMgr::instance().getObservation(name);
+ ASSERT_TRUE(stat);
+ EXPECT_EQ(0, stat->getInteger().first);
+ } else {
+ // Check that the lease is really gone in the database
+ // get lease by address
+ l = LeaseMgrFactory::instance().getLease6(type, release_addr);
+ ASSERT_TRUE(l);
- // get lease by subnetid/duid/iaid combination
- l = LeaseMgrFactory::instance().getLease6(type, *duid_, iaid,
- subnet_->getID());
- ASSERT_FALSE(l);
+ EXPECT_TRUE(l->expired());
- // We should have decremented the address counter
- ObservationPtr stat = StatsMgr::instance().getObservation(name);
- ASSERT_TRUE(stat);
- EXPECT_EQ(0, stat->getInteger().first);
+ // get lease by subnetid/duid/iaid combination
+ l = LeaseMgrFactory::instance().getLease6(type, *duid_, iaid,
+ subnet_->getID());
+ ASSERT_TRUE(l);
+
+ EXPECT_TRUE(l->expired());
+
+ // We should have decremented the address counter
+ stat = StatsMgr::instance().getObservation(name);
+ ASSERT_TRUE(stat);
+ EXPECT_EQ(before, stat->getInteger().first);
+ }
}
void
@@ -815,8 +841,9 @@ Dhcpv6SrvTest::configure(const std::string& config,
const bool commit,
const bool open_sockets,
const bool create_managers,
- const bool test) {
- configure(config, srv_, commit, open_sockets, create_managers, test);
+ const bool test,
+ const bool disable_affinity) {
+ configure(config, srv_, commit, open_sockets, create_managers, test, disable_affinity);
}
void
@@ -825,7 +852,8 @@ Dhcpv6SrvTest::configure(const std::string& config,
const bool commit,
const bool open_sockets,
const bool create_managers,
- const bool test) {
+ const bool test,
+ const bool disable_affinity) {
setenv("KEA_LFC_EXECUTABLE", KEA_LFC_EXECUTABLE, 1);
MultiThreadingCriticalSection cs;
ConstElementPtr json;
@@ -863,6 +891,12 @@ Dhcpv6SrvTest::configure(const std::string& config,
} );
}
+ if (disable_affinity) {
+ auto expiration_cfg = CfgMgr::instance().getStagingCfg()->getCfgExpiration();
+ expiration_cfg->setFlushReclaimedTimerWaitTime(0);
+ expiration_cfg->setHoldReclaimedTime(0);
+ }
+
try {
CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
} catch (const std::exception& ex) {
diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.h b/src/bin/dhcp6/tests/dhcp6_test_utils.h
index 856f1a40f6..48953ad39f 100644
--- a/src/bin/dhcp6/tests/dhcp6_test_utils.h
+++ b/src/bin/dhcp6/tests/dhcp6_test_utils.h
@@ -339,8 +339,8 @@ public:
NakedDhcpv6SrvTest();
// Generate IA_NA or IA_PD option with specified parameters
- boost::shared_ptr<isc::dhcp::Option6IA> generateIA
- (uint16_t type, uint32_t iaid, uint32_t t1, uint32_t t2);
+ boost::shared_ptr<isc::dhcp::Option6IA> generateIA(uint16_t type, uint32_t iaid,
+ uint32_t t1, uint32_t t2);
/// @brief generates interface-id option, based on text
///
@@ -400,8 +400,7 @@ public:
// Checks if server response (ADVERTISE or REPLY) includes proper
// server-id.
void checkServerId(const isc::dhcp::Pkt6Ptr& rsp,
- const isc::dhcp::OptionPtr& expected_srvid)
- {
+ const isc::dhcp::OptionPtr& expected_srvid) {
// check that server included its server-id
isc::dhcp::OptionPtr tmp = rsp->getOption(D6O_SERVERID);
EXPECT_EQ(tmp->getType(), expected_srvid->getType() );
@@ -412,8 +411,7 @@ public:
// Checks if server response (ADVERTISE or REPLY) includes proper
// client-id.
void checkClientId(const isc::dhcp::Pkt6Ptr& rsp,
- const isc::dhcp::OptionPtr& expected_clientid)
- {
+ const isc::dhcp::OptionPtr& expected_clientid) {
// check that server included our own client-id
isc::dhcp::OptionPtr tmp = rsp->getOption(D6O_CLIENTID);
ASSERT_TRUE(tmp);
@@ -429,8 +427,7 @@ public:
uint8_t expected_message_type,
uint32_t expected_transid,
uint16_t expected_status_code,
- uint32_t expected_t1, uint32_t expected_t2)
- {
+ uint32_t expected_t1, uint32_t expected_t2) {
// Check if we get response at all
checkResponse(rsp, expected_message_type, expected_transid);
@@ -463,14 +460,12 @@ public:
/// @param expected_t1 expected T1 in IA_NA option
/// @param expected_t2 expected T2 in IA_NA option
/// @param check_addr whether to check for address with 0 lifetimes
- void checkIA_NAStatusCode
- (const boost::shared_ptr<isc::dhcp::Option6IA>& ia,
- uint16_t expected_status_code, uint32_t expected_t1,
- uint32_t expected_t2, bool check_addr = true);
+ void checkIA_NAStatusCode(const boost::shared_ptr<isc::dhcp::Option6IA>& ia,
+ uint16_t expected_status_code, uint32_t expected_t1,
+ uint32_t expected_t2, bool check_addr = true);
void checkMsgStatusCode(const isc::dhcp::Pkt6Ptr& msg,
- uint16_t expected_status)
- {
+ uint16_t expected_status) {
isc::dhcp::Option6StatusCodePtr status =
boost::dynamic_pointer_cast<isc::dhcp::Option6StatusCode>
(msg->getOption(D6O_STATUS_CODE));
@@ -571,11 +566,14 @@ public:
/// @param create_managers A boolean flag indicating if managers should be
/// recreated.
/// @param test A boolean flag which indicates if only testing config.
+ /// @param disable_affinity A boolean flag which indicates if lease affinity
+ /// should be disabled.
void configure(const std::string& config,
const bool commit = true,
const bool open_sockets = false,
const bool create_managers = true,
- const bool test = false);
+ const bool test = false,
+ const bool disable_affinity = true);
/// @brief Configure the DHCPv6 server using the JSON string.
///
@@ -588,12 +586,15 @@ public:
/// @param create_managers A boolean flag indicating if managers should be
/// recreated.
/// @param test A boolean flag which indicates if only testing config.
+ /// @param disable_affinity A boolean flag which indicates if lease affinity
+ /// should be disabled.
void configure(const std::string& config,
NakedDhcpv6Srv& srv,
const bool commit = true,
const bool open_sockets = false,
const bool create_managers = true,
- const bool test = false);
+ const bool test = false,
+ const bool disable_affinity = true);
/// @brief Checks that server response (ADVERTISE or REPLY) contains proper
/// IA_NA option
@@ -810,10 +811,13 @@ public:
/// @param type type (TYPE_NA or TYPE_PD)
/// @param existing address to be preinserted into the database
/// @param release_addr address being sent in RELEASE
+ /// @param disable_affinity A boolean flag which indicates if lease affinity
+ /// should be disabled.
void
testReleaseBasic(isc::dhcp::Lease::Type type,
const isc::asiolink::IOAddress& existing,
- const isc::asiolink::IOAddress& release_addr);
+ const isc::asiolink::IOAddress& release_addr,
+ const bool disable_affinity = true);
/// @brief Performs negative RELEASE test
///
diff --git a/src/bin/dhcp6/tests/fqdn_unittest.cc b/src/bin/dhcp6/tests/fqdn_unittest.cc
index 683a71cf62..e3757df635 100644
--- a/src/bin/dhcp6/tests/fqdn_unittest.cc
+++ b/src/bin/dhcp6/tests/fqdn_unittest.cc
@@ -261,7 +261,6 @@ public:
pkt->addOption(opt_ia);
}
-
/// @brief Adds IA option to the message.
///
/// Added option holds status code.
@@ -484,7 +483,6 @@ public:
}
}
-
/// @brief Tests that the client's message holding an FQDN is processed
/// and that lease is acquired.
///
@@ -523,18 +521,18 @@ public:
ASSERT_FALSE(drop);
if (msg_type == DHCPV6_SOLICIT) {
- ASSERT_NO_THROW(reply = srv_->processSolicit(ctx));
+ ASSERT_NO_THROW(reply = srv_->processSolicit(ctx));
} else if (msg_type == DHCPV6_REQUEST) {
- ASSERT_NO_THROW(reply = srv_->processRequest(ctx));
+ ASSERT_NO_THROW(reply = srv_->processRequest(ctx));
} else if (msg_type == DHCPV6_RENEW) {
- ASSERT_NO_THROW(reply = srv_->processRenew(ctx));
+ ASSERT_NO_THROW(reply = srv_->processRenew(ctx));
} else if (msg_type == DHCPV6_RELEASE) {
// For Release no lease will be acquired so we have to leave
// function here.
- ASSERT_NO_THROW(reply = srv_->processRelease(ctx));
+ ASSERT_NO_THROW(reply = srv_->processRelease(ctx));
return;
} else {
// We are not interested in testing other message types.
@@ -944,7 +942,6 @@ TEST_F(FqdnDhcpv6SrvTest, noRemovalsWhenDisabled) {
ASSERT_NO_THROW(queueNCR(CHG_REMOVE, lease_));
}
-
// Test creation of the NameChangeRequest to remove reverse mapping for the
// given lease.
TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestRev) {
@@ -1038,7 +1035,6 @@ TEST_F(FqdnDhcpv6SrvTest, processTwoRequestsDiffFqdn) {
"FAAAA3EBD29826B5C907B2C9268A6F52",
0, 4000);
-
// Client may send another request message with a new domain-name. In this
// case the same lease will be returned. The existing DNS entry needs to
// be replaced with a new one. Server should determine that the different
@@ -1085,7 +1081,6 @@ TEST_F(FqdnDhcpv6SrvTest, processTwoRequestsSameFqdn) {
"FAAAA3EBD29826B5C907B2C9268A6F52",
0, 4000);
-
// Client may send another request message with a same domain-name. In this
// case the same lease will be returned. The existing DNS entry should be
// left alone, so we expect no NameChangeRequests queued..
@@ -1123,7 +1118,6 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestSolicit) {
}
-
// Test that client may send Request followed by the Renew, both holding
// FQDN options, but each option holding different domain-name. The Renew
// should result in generation of the two NameChangeRequests, one to remove
@@ -1236,7 +1230,6 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestRenewFqdnFlags) {
// Queue should be empty.
ASSERT_EQ(0, d2_mgr_.getQueueSize());
-
// Renew with both N and S flags = 0. This tells the server to update
// both directions, which should change forward flag to true. This should
// generate a reverse only remove and a dual add.
@@ -1276,8 +1269,10 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestRenewFqdnFlags) {
lease_->cltt_, lease_->valid_lft_);
}
-
TEST_F(FqdnDhcpv6SrvTest, processRequestRelease) {
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setFlushReclaimedTimerWaitTime(0);
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setHoldReclaimedTime(0);
+
// Create a Request message with FQDN option and generate server's
// response using processRequest function. This will result in the
// creation of a new lease and the appropriate NameChangeRequest
@@ -1311,6 +1306,33 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestRelease) {
lease_->cltt_, lease_->valid_lft_);
}
+TEST_F(FqdnDhcpv6SrvTest, processRequestReleaseNoDelete) {
+ // Create a Request message with FQDN option and generate server's
+ // response using processRequest function. This will result in the
+ // creation of a new lease and the appropriate NameChangeRequest
+ // to add both reverse and forward mapping to DNS.
+ testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",
+ "myhost.example.com.");
+
+ // The lease should have been recorded in the database.
+ lease_ = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ IOAddress("2001:db8:1:1::dead:beef"));
+ ASSERT_TRUE(lease_);
+
+ ASSERT_EQ(1, d2_mgr_.getQueueSize());
+ verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
+ "2001:db8:1:1::dead:beef",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, lease_->valid_lft_);
+
+ // Client may send Release message. In this case the lease should be
+ // expired and no NameChangeRequest to remove DNS entries is generated.
+ testProcessMessage(DHCPV6_RELEASE, "otherhost.example.com",
+ "otherhost.example.com.");
+ ASSERT_EQ(0, d2_mgr_.getQueueSize());
+}
+
// Checks that the server include DHCPv6 Client FQDN option in its
// response even when client doesn't request this option using ORO.
TEST_F(FqdnDhcpv6SrvTest, processRequestWithoutFqdn) {
@@ -1607,7 +1629,6 @@ TEST_F(FqdnDhcpv6SrvTest, replaceClientNameModeTest) {
CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
}
-
// Verifies that setting hostname-char-set sanitizes FQDN option
// values received from clients.
TEST_F(FqdnDhcpv6SrvTest, sanitizeFqdn) {
diff --git a/src/bin/dhcp6/tests/hooks_unittest.cc b/src/bin/dhcp6/tests/hooks_unittest.cc
index fac2d438ac..99be8bd558 100644
--- a/src/bin/dhcp6/tests/hooks_unittest.cc
+++ b/src/bin/dhcp6/tests/hooks_unittest.cc
@@ -8,26 +8,28 @@
#include <asiolink/io_address.h>
#include <asiolink/io_service.h>
+#include <cc/command_interpreter.h>
+#include <config/command_mgr.h>
#include <dhcp/dhcp6.h>
#include <dhcp/duid.h>
-#include <dhcp6/json_config_parser.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
+#include <dhcp/tests/pkt_captures.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcpsrv/utils.h>
-#include <util/buffer.h>
-#include <util/range_utilities.h>
-#include <hooks/server_hooks.h>
-#include <hooks/callout_manager.h>
-#include <dhcp6/tests/dhcp6_test_utils.h>
-#include <dhcp6/tests/dhcp6_client.h>
#include <dhcp6/ctrl_dhcp6_srv.h>
-#include <dhcp/tests/iface_mgr_test_config.h>
-#include <dhcp/tests/pkt_captures.h>
-#include <cc/command_interpreter.h>
+#include <dhcp6/json_config_parser.h>
+#include <dhcp6/tests/dhcp6_client.h>
+#include <dhcp6/tests/dhcp6_test_utils.h>
#include <dhcp6/tests/marker_file.h>
#include <dhcp6/tests/test_libraries.h>
+#include <hooks/server_hooks.h>
+#include <hooks/hooks_manager.h>
+#include <hooks/callout_manager.h>
#include <stats/stats_mgr.h>
+#include <util/buffer.h>
+#include <util/range_utilities.h>
#include <util/multi_threading_mgr.h>
#include <boost/scoped_ptr.hpp>
@@ -37,15 +39,16 @@
#include <iostream>
#include <sstream>
-using namespace isc;
+
+using namespace isc::asiolink;
using namespace isc::config;
using namespace isc::data;
-using namespace isc::dhcp::test;
-using namespace isc::asiolink;
using namespace isc::dhcp;
-using namespace isc::util;
+using namespace isc::dhcp::test;
using namespace isc::hooks;
using namespace isc::stats;
+using namespace isc::util;
+
using namespace std;
// namespace has to be named, because friends are defined in Dhcpv6Srv class
@@ -57,19 +60,22 @@ TEST_F(Dhcpv6SrvTest, Hooks) {
NakedDhcpv6Srv srv(0);
// check if appropriate hooks are registered
- int hook_index_buffer6_receive = -1;
- int hook_index_buffer6_send = -1;
- int hook_index_lease6_renew = -1;
- int hook_index_lease6_release = -1;
- int hook_index_lease6_rebind = -1;
- int hook_index_lease6_decline = -1;
- int hook_index_pkt6_received = -1;
- int hook_index_select_subnet = -1;
+ int hook_index_dhcp6_srv_configured = -1;
+ int hook_index_buffer6_receive = -1;
+ int hook_index_buffer6_send = -1;
+ int hook_index_lease6_renew = -1;
+ int hook_index_lease6_release = -1;
+ int hook_index_lease6_rebind = -1;
+ int hook_index_lease6_decline = -1;
+ int hook_index_pkt6_receive = -1;
+ int hook_index_pkt6_send = -1;
+ int hook_index_select_subnet = -1;
int hook_index_leases6_committed = -1;
- int hook_index_pkt6_send = -1;
- int hook_index_host6_identifier = -1;
+ int hook_index_host6_identifier = -1;
// check if appropriate indexes are set
+ EXPECT_NO_THROW(hook_index_dhcp6_srv_configured = ServerHooks::getServerHooks()
+ .getIndex("dhcp6_srv_configured"));
EXPECT_NO_THROW(hook_index_buffer6_receive = ServerHooks::getServerHooks()
.getIndex("buffer6_receive"));
EXPECT_NO_THROW(hook_index_buffer6_send = ServerHooks::getServerHooks()
@@ -82,29 +88,29 @@ TEST_F(Dhcpv6SrvTest, Hooks) {
.getIndex("lease6_rebind"));
EXPECT_NO_THROW(hook_index_lease6_decline = ServerHooks::getServerHooks()
.getIndex("lease6_decline"));
- EXPECT_NO_THROW(hook_index_pkt6_received = ServerHooks::getServerHooks()
+ EXPECT_NO_THROW(hook_index_pkt6_receive = ServerHooks::getServerHooks()
.getIndex("pkt6_receive"));
+ EXPECT_NO_THROW(hook_index_pkt6_send = ServerHooks::getServerHooks()
+ .getIndex("pkt6_send"));
EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
.getIndex("subnet6_select"));
EXPECT_NO_THROW(hook_index_leases6_committed = ServerHooks::getServerHooks()
.getIndex("leases6_committed"));
- EXPECT_NO_THROW(hook_index_pkt6_send = ServerHooks::getServerHooks()
- .getIndex("pkt6_send"));
EXPECT_NO_THROW(hook_index_host6_identifier = ServerHooks::getServerHooks()
.getIndex("host6_identifier"));
-
- EXPECT_TRUE(hook_index_pkt6_received > 0);
- EXPECT_TRUE(hook_index_select_subnet > 0);
+ EXPECT_TRUE(hook_index_dhcp6_srv_configured > 0);
+ EXPECT_TRUE(hook_index_buffer6_receive > 0);
+ EXPECT_TRUE(hook_index_buffer6_send > 0);
+ EXPECT_TRUE(hook_index_lease6_renew > 0);
+ EXPECT_TRUE(hook_index_lease6_release > 0);
+ EXPECT_TRUE(hook_index_lease6_rebind > 0);
+ EXPECT_TRUE(hook_index_lease6_decline > 0);
+ EXPECT_TRUE(hook_index_pkt6_receive > 0);
+ EXPECT_TRUE(hook_index_pkt6_send > 0);
+ EXPECT_TRUE(hook_index_select_subnet > 0);
EXPECT_TRUE(hook_index_leases6_committed > 0);
- EXPECT_TRUE(hook_index_pkt6_send > 0);
- EXPECT_TRUE(hook_index_buffer6_receive > 0);
- EXPECT_TRUE(hook_index_buffer6_send > 0);
- EXPECT_TRUE(hook_index_lease6_renew > 0);
- EXPECT_TRUE(hook_index_lease6_release > 0);
- EXPECT_TRUE(hook_index_lease6_rebind > 0);
- EXPECT_TRUE(hook_index_lease6_decline > 0);
- EXPECT_TRUE(hook_index_host6_identifier > 0);
+ EXPECT_TRUE(hook_index_host6_identifier > 0);
}
/// @brief a class dedicated to Hooks testing in DHCPv6 server
@@ -120,9 +126,7 @@ class HooksDhcpv6SrvTest : public Dhcpv6SrvTest {
public:
/// @brief creates Dhcpv6Srv and prepares buffers for callouts
- HooksDhcpv6SrvTest()
- : Dhcpv6SrvTest() {
-
+ HooksDhcpv6SrvTest() : Dhcpv6SrvTest() {
HooksManager::setTestMode(false);
bool status = HooksManager::unloadLibraries();
if (!status) {
@@ -149,10 +153,11 @@ public:
// Clear static buffers
resetCalloutBuffers();
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("dhcp6_srv_configured");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer6_receive");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer6_send");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt6_receive");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt6_send");
- HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer6_send");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("subnet6_select");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("leases6_committed");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease6_renew");
@@ -161,20 +166,20 @@ public:
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease6_decline");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("host6_identifier");
- // Clear statistics.
- StatsMgr::instance().removeAll();
-
HooksManager::setTestMode(false);
bool status = HooksManager::unloadLibraries();
if (!status) {
cerr << "(fixture dtor) unloadLibraries failed" << endl;
}
+
+ // Clear statistics.
+ StatsMgr::instance().removeAll();
}
/// @brief creates an option with specified option code
///
/// This method is static, because it is used from callouts
- /// that do not have a pointer to HooksDhcpv6SSrvTest object
+ /// that do not have a pointer to HooksDhcpv6SrvTest object
///
/// @param option_code code of option to be created
///
@@ -204,12 +209,12 @@ public:
EXPECT_TRUE(callout_handle->getArgumentNames().empty());
}
- /// test callback that stores received callout name and pkt6 value
+ /// Test callback that stores received callout name and pkt6 value
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- pkt6_receive_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("pkt6_receive");
+ buffer6_receive_callout(CalloutHandle& callout_handle) {
+ callback_name_ = string("buffer6_receive");
callout_handle.getArgument("query6", callback_qry_pkt6_);
@@ -222,77 +227,84 @@ public:
return (0);
}
- /// test callback that changes client-id value
+ /// Test callback that changes first byte of client-id value
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- pkt6_receive_change_clientid(CalloutHandle& callout_handle) {
+ buffer6_receive_change_clientid(CalloutHandle& callout_handle) {
Pkt6Ptr pkt;
callout_handle.getArgument("query6", pkt);
- // Get rid of the old client-id
- pkt->delOption(D6O_CLIENTID);
-
- // Add a new option
- pkt->addOption(createOption(D6O_CLIENTID));
+ // If there is at least one option with data
+ if (pkt->data_.size() > Pkt6::DHCPV6_PKT_HDR_LEN + Option::OPTION6_HDR_LEN) {
+ // Offset of the first byte of the first option. Let's set this byte
+ // to some new value that we could later check
+ pkt->data_[Pkt6::DHCPV6_PKT_HDR_LEN + Option::OPTION6_HDR_LEN] = 0xff;
+ }
// Carry on as usual
- return pkt6_receive_callout(callout_handle);
+ return buffer6_receive_callout(callout_handle);
}
/// Test callback that deletes client-id
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- pkt6_receive_delete_clientid(CalloutHandle& callout_handle) {
+ buffer6_receive_delete_clientid(CalloutHandle& callout_handle) {
Pkt6Ptr pkt;
callout_handle.getArgument("query6", pkt);
- // Get rid of the old client-id
- pkt->delOption(D6O_CLIENTID);
+ // this is modified SOLICIT (with missing mandatory client-id)
+ uint8_t data[] = {
+ 1, // type 1 = SOLICIT
+ 0xca, 0xfe, 0x01, // trans-id = 0xcafe01
+ 0, 3, // option type 3 (IA_NA)
+ 0, 12, // option length 12
+ 0, 0, 0, 1, // iaid = 1
+ 0, 0, 0, 0, // T1 = 0
+ 0, 0, 0, 0 // T2 = 0
+ };
+
+ OptionBuffer modifiedMsg(data, data + sizeof(data));
+
+ pkt->data_ = modifiedMsg;
// Carry on as usual
- return pkt6_receive_callout(callout_handle);
+ return buffer6_receive_callout(callout_handle);
}
/// Test callback that sets skip flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- pkt6_receive_skip(CalloutHandle& callout_handle) {
-
- Pkt6Ptr pkt;
- callout_handle.getArgument("query6", pkt);
+ buffer6_receive_skip(CalloutHandle& callout_handle) {
callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
// Carry on as usual
- return pkt6_receive_callout(callout_handle);
+ return buffer6_receive_callout(callout_handle);
}
/// Test callback that sets drop flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- pkt6_receive_drop(CalloutHandle& callout_handle) {
-
- Pkt6Ptr pkt;
- callout_handle.getArgument("query6", pkt);
+ buffer6_receive_drop(CalloutHandle& callout_handle) {
callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
// Carry on as usual
- return pkt6_receive_callout(callout_handle);
+ return buffer6_receive_callout(callout_handle);
}
/// Test callback that stores received callout name and pkt6 value
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- buffer6_receive_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("buffer6_receive");
+ pkt6_receive_callout(CalloutHandle& callout_handle) {
+ callback_name_ = string("pkt6_receive");
callout_handle.getArgument("query6", callback_qry_pkt6_);
@@ -305,74 +317,69 @@ public:
return (0);
}
- /// Test callback that changes first byte of client-id value
+ /// Test callback that changes client-id value
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- buffer6_receive_change_clientid(CalloutHandle& callout_handle) {
+ pkt6_receive_change_clientid(CalloutHandle& callout_handle) {
Pkt6Ptr pkt;
callout_handle.getArgument("query6", pkt);
- // If there is at least one option with data
- if (pkt->data_.size() > Pkt6::DHCPV6_PKT_HDR_LEN + Option::OPTION6_HDR_LEN) {
- // Offset of the first byte of the first option. Let's set this byte
- // to some new value that we could later check
- pkt->data_[Pkt6::DHCPV6_PKT_HDR_LEN + Option::OPTION6_HDR_LEN] = 0xff;
- }
+ // Get rid of the old client-id
+ pkt->delOption(D6O_CLIENTID);
+
+ // Add a new option
+ pkt->addOption(createOption(D6O_CLIENTID));
// Carry on as usual
- return buffer6_receive_callout(callout_handle);
+ return pkt6_receive_callout(callout_handle);
}
/// Test callback that deletes client-id
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- buffer6_receive_delete_clientid(CalloutHandle& callout_handle) {
+ pkt6_receive_delete_clientid(CalloutHandle& callout_handle) {
Pkt6Ptr pkt;
callout_handle.getArgument("query6", pkt);
- // this is modified SOLICIT (with missing mandatory client-id)
- uint8_t data[] = {
- 1, // type 1 = SOLICIT
- 0xca, 0xfe, 0x01, // trans-id = 0xcafe01
- 0, 3, // option type 3 (IA_NA)
- 0, 12, // option length 12
- 0, 0, 0, 1, // iaid = 1
- 0, 0, 0, 0, // T1 = 0
- 0, 0, 0, 0 // T2 = 0
- };
-
- OptionBuffer modifiedMsg(data, data + sizeof(data));
-
- pkt->data_ = modifiedMsg;
+ // Get rid of the old client-id
+ pkt->delOption(D6O_CLIENTID);
- // carry on as usual
- return buffer6_receive_callout(callout_handle);
+ // Carry on as usual
+ return pkt6_receive_callout(callout_handle);
}
/// Test callback that sets skip flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- buffer6_receive_skip(CalloutHandle& callout_handle) {
+ pkt6_receive_skip(CalloutHandle& callout_handle) {
+
+ Pkt6Ptr pkt;
+ callout_handle.getArgument("query6", pkt);
+
callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
// Carry on as usual
- return buffer6_receive_callout(callout_handle);
+ return pkt6_receive_callout(callout_handle);
}
/// Test callback that sets drop flag
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
- buffer6_receive_drop(CalloutHandle& callout_handle) {
+ pkt6_receive_drop(CalloutHandle& callout_handle) {
+
+ Pkt6Ptr pkt;
+ callout_handle.getArgument("query6", pkt);
+
callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
// Carry on as usual
- return buffer6_receive_callout(callout_handle);
+ return pkt6_receive_callout(callout_handle);
}
/// Test callback that stores received callout name and pkt6 value
@@ -464,17 +471,17 @@ public:
return pkt6_send_callout(callout_handle);
}
- /// @brief Test callback that stores response packet.
+ /// Test callback that stores response packet.
/// @param callout_handle handle passed by the hooks framework.
/// @return always 0
static int
buffer6_send_callout(CalloutHandle& callout_handle) {
callback_name_ = string("buffer6_send");
- callback_argument_names_ = callout_handle.getArgumentNames();
-
callout_handle.getArgument("response6", callback_resp_pkt6_);
+ callback_argument_names_ = callout_handle.getArgumentNames();
+
if (callback_resp_pkt6_) {
callback_resp_options_copy_ = callback_resp_pkt6_->isCopyRetrievedOptions();
}
@@ -490,7 +497,7 @@ public:
callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- // carry on as usual
+ // Carry on as usual
return buffer6_send_callout(callout_handle);
}
@@ -573,7 +580,7 @@ public:
return subnet6_select_callout(callout_handle);
}
- /// Test callback that stores received callout name and pkt6 value
+ /// Test callback that stores received callout name and subnet6 values
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
@@ -709,7 +716,6 @@ public:
return (lease6_rebind_callout(callout_handle));
}
-
/// Test callback that stores received callout name passed parameters
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
@@ -753,9 +759,7 @@ public:
return (0);
}
- /// Lease6_decline test callback
- ///
- /// Stores all parameters in callback_* fields.
+ /// Test lease6_decline callback that stores received parameters.
///
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
@@ -772,7 +776,7 @@ public:
return (0);
}
- /// Lease6_decline callout that sets status to SKIP
+ /// Test lease6_decline callback that sets next step to SKIP.
///
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
@@ -783,7 +787,7 @@ public:
return (lease6_decline_callout(callout_handle));
}
- /// Lease6_decline callout that sets status to DROP
+ /// Test lease6_decline callback that sets next step to DROP.
///
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
@@ -848,7 +852,7 @@ public:
return (0);
}
- /// @brief Test host6_identifier by setting identifier to "foo"
+ /// @brief Test host6_identifier callback by setting identifier to "foo"
///
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
@@ -904,7 +908,6 @@ public:
return (0);
}
-
/// Resets buffers used to store data received by callouts
void resetCalloutBuffers() {
callback_name_ = string("");
@@ -954,8 +957,10 @@ public:
/// Pointer to lease6 structure returned in the leases6_committed callout
static Lease6Ptr callback_lease6_;
- /// Pointers to lease6 structures returned in the leases6_committed callout
+ /// Pointer to lease6 structure returned in the leases6_committed callout
static Lease6CollectionPtr callback_new_leases6_;
+
+ /// Pointer to lease6 structure returned in the leases6_committed callout
static Lease6CollectionPtr callback_deleted_leases6_;
/// Pointer to IA_NA option being renewed or rebound
@@ -993,11 +998,11 @@ Pkt6Ptr HooksDhcpv6SrvTest::callback_qry_pkt6_;
Pkt6Ptr HooksDhcpv6SrvTest::callback_resp_pkt6_;
Subnet6Ptr HooksDhcpv6SrvTest::callback_subnet6_;
const Subnet6Collection* HooksDhcpv6SrvTest::callback_subnet6collection_;
-vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
Lease6Ptr HooksDhcpv6SrvTest::callback_lease6_;
Lease6CollectionPtr HooksDhcpv6SrvTest::callback_new_leases6_;
Lease6CollectionPtr HooksDhcpv6SrvTest::callback_deleted_leases6_;
boost::shared_ptr<Option6IA> HooksDhcpv6SrvTest::callback_ia_na_;
+vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
bool HooksDhcpv6SrvTest::callback_qry_options_copy_;
bool HooksDhcpv6SrvTest::callback_resp_options_copy_;
@@ -1007,8 +1012,7 @@ public:
/// @brief Pointer to the tested server object
boost::shared_ptr<NakedDhcpv6Srv> server_;
- LoadUnloadDhcpv6SrvTest()
- : Dhcpv6SrvTest() {
+ LoadUnloadDhcpv6SrvTest() : Dhcpv6SrvTest() {
reset();
MultiThreadingMgr::instance().setMode(false);
}
@@ -1037,13 +1041,12 @@ public:
}
};
-
// Checks if callouts installed on buffer6_receive are indeed called and the
// all necessary parameters are passed.
//
// Note that the test name does not follow test naming convention,
// but the proper hook name is "buffer6_receive".
-TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Receive) {
+TEST_F(HooksDhcpv6SrvTest, buffer6ReceiveSimple) {
// Install buffer6_receive_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1082,7 +1085,7 @@ TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Receive) {
// Checks if callouts installed on buffer6_receive is able to change
// the values and the parameters are indeed used by the server.
-TEST_F(HooksDhcpv6SrvTest, valueChangeBuffer6Receive) {
+TEST_F(HooksDhcpv6SrvTest, buffer6ReceiveValueChange) {
// Install buffer6_receive_change_clientid
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1122,7 +1125,7 @@ TEST_F(HooksDhcpv6SrvTest, valueChangeBuffer6Receive) {
// Checks if callouts installed on buffer6_receive is able to delete
// existing options and that change impacts server processing (mandatory
// client-id option is deleted, so the packet is expected to be dropped)
-TEST_F(HooksDhcpv6SrvTest, deleteClientIdBuffer6Receive) {
+TEST_F(HooksDhcpv6SrvTest, buffer6ReceiveDeleteClientId) {
// Install buffer6_receive_delete_clientid
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1147,9 +1150,9 @@ TEST_F(HooksDhcpv6SrvTest, deleteClientIdBuffer6Receive) {
checkCalloutHandleReset(sol);
}
-// Checks if callouts installed on buffer6_received is able to set skip flag that
+// Checks if callouts installed on buffer6_receive is able to set skip flag that
// will cause the server to not process the packet (drop), even though it is valid.
-TEST_F(HooksDhcpv6SrvTest, skipBuffer6Receive) {
+TEST_F(HooksDhcpv6SrvTest, buffer6ReceiveSkip) {
// Install buffer6_receive_skip
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1174,9 +1177,9 @@ TEST_F(HooksDhcpv6SrvTest, skipBuffer6Receive) {
checkCalloutHandleReset(sol);
}
-// Checks if callouts installed on buffer6_received is able to set drop flag that
+// Checks if callouts installed on buffer6_receive is able to set drop flag that
// will cause the server to not process the packet (drop), even though it is valid.
-TEST_F(HooksDhcpv6SrvTest, dropBuffer6Receive) {
+TEST_F(HooksDhcpv6SrvTest, buffer6ReceiveDrop) {
// Install buffer6_receive_drop
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1206,7 +1209,7 @@ TEST_F(HooksDhcpv6SrvTest, dropBuffer6Receive) {
//
// Note that the test name does not follow test naming convention,
// but the proper hook name is "pkt6_receive".
-TEST_F(HooksDhcpv6SrvTest, simplePkt6Receive) {
+TEST_F(HooksDhcpv6SrvTest, pkt6ReceiveSimple) {
// Install pkt6_receive_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1245,7 +1248,7 @@ TEST_F(HooksDhcpv6SrvTest, simplePkt6Receive) {
// Checks if callouts installed on pkt6_received is able to change
// the values and the parameters are indeed used by the server.
-TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Receive) {
+TEST_F(HooksDhcpv6SrvTest, pkt6ReceiveValueChange) {
// Install pkt6_receive_change_clientid
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1284,7 +1287,7 @@ TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Receive) {
// Checks if callouts installed on pkt6_received is able to delete
// existing options and that change impacts server processing (mandatory
// client-id option is deleted, so the packet is expected to be dropped)
-TEST_F(HooksDhcpv6SrvTest, deleteClientIdPkt6Receive) {
+TEST_F(HooksDhcpv6SrvTest, pkt6ReceiveDeleteClientId) {
// Install pkt6_receive_delete_clientid
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1311,7 +1314,7 @@ TEST_F(HooksDhcpv6SrvTest, deleteClientIdPkt6Receive) {
// Checks if callouts installed on pkt6_received is able to set skip flag that
// will cause the server to not process the packet (drop), even though it is valid.
-TEST_F(HooksDhcpv6SrvTest, skipPkt6Receive) {
+TEST_F(HooksDhcpv6SrvTest, pkt6ReceiveSkip) {
// Install pkt6_receive_skip
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1338,7 +1341,7 @@ TEST_F(HooksDhcpv6SrvTest, skipPkt6Receive) {
// Checks if callouts installed on pkt6_received is able to set drop flag that
// will cause the server to not process the packet (drop), even though it is valid.
-TEST_F(HooksDhcpv6SrvTest, dropPkt6Receive) {
+TEST_F(HooksDhcpv6SrvTest, pkt6ReceiveDrop) {
// Install pkt6_receive_drop
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1363,10 +1366,9 @@ TEST_F(HooksDhcpv6SrvTest, dropPkt6Receive) {
checkCalloutHandleReset(sol);
}
-
// Checks if callouts installed on pkt6_send are indeed called and the
// all necessary parameters are passed.
-TEST_F(HooksDhcpv6SrvTest, simplePkt6Send) {
+TEST_F(HooksDhcpv6SrvTest, pkt6SendSimple) {
// Install pkt6_send_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1393,7 +1395,9 @@ TEST_F(HooksDhcpv6SrvTest, simplePkt6Send) {
// Check that pkt6 argument passing was successful and returned proper
// values
+ ASSERT_TRUE(callback_qry_pkt6_);
EXPECT_TRUE(callback_qry_pkt6_.get() == sol.get());
+ ASSERT_TRUE(callback_resp_pkt6_);
EXPECT_TRUE(callback_resp_pkt6_.get() == adv.get());
// Check that all expected parameters are there
@@ -1412,7 +1416,7 @@ TEST_F(HooksDhcpv6SrvTest, simplePkt6Send) {
// Checks if callouts installed on pkt6_send is able to change
// the values and the packet sent contains those changes
-TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Send) {
+TEST_F(HooksDhcpv6SrvTest, pkt6SendValueChange) {
// Install pkt6_send_change_serverid
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1452,7 +1456,7 @@ TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Send) {
// existing options and that server applies those changes. In particular,
// we are trying to send a packet without server-id. The packet should
// be sent
-TEST_F(HooksDhcpv6SrvTest, deleteServerIdPkt6Send) {
+TEST_F(HooksDhcpv6SrvTest, pkt6SendDeleteServerId) {
// Install pkt6_send_delete_serverid
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1486,7 +1490,7 @@ TEST_F(HooksDhcpv6SrvTest, deleteServerIdPkt6Send) {
// Checks if callouts installed on pkt6_skip is able to set skip flag that
// will cause the server to send an empty response.
-TEST_F(HooksDhcpv6SrvTest, skipPkt6Send) {
+TEST_F(HooksDhcpv6SrvTest, pkt6SendSkip) {
// Install pkt6_send_skip
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1507,8 +1511,8 @@ TEST_F(HooksDhcpv6SrvTest, skipPkt6Send) {
// Check that the server send the packet
ASSERT_EQ(1, srv_->fake_sent_.size());
- // But the sent packet should have 0 length (we told the server to
- // skip pack(), but did not do packing outselves)
+ // Get the first packet and check that it has zero length (i.e. the server
+ // did not do packing on its own)
Pkt6Ptr sent = srv_->fake_sent_.front();
// The actual size of sent packet should be 0
@@ -1520,7 +1524,7 @@ TEST_F(HooksDhcpv6SrvTest, skipPkt6Send) {
// Checks if callouts installed on pkt6_drop is able to set drop flag that
// will cause the server to not process the packet (drop), even though it is valid.
-TEST_F(HooksDhcpv6SrvTest, dropPkt6Send) {
+TEST_F(HooksDhcpv6SrvTest, pkt6SendDrop) {
// Install pkt6_send_drop
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1547,7 +1551,7 @@ TEST_F(HooksDhcpv6SrvTest, dropPkt6Send) {
// Checks if callouts installed on buffer6_send are indeed called and the
// all necessary parameters are passed.
-TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Send) {
+TEST_F(HooksDhcpv6SrvTest, buffer6SendSimple) {
// Install buffer6_send_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -1572,8 +1576,7 @@ TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Send) {
ASSERT_EQ(1, srv_->fake_sent_.size());
Pkt6Ptr adv = srv_->fake_sent_.front();
- // Check that pkt6 argument passing was successful and returned proper
- // values
+ // Check that pkt6 argument passing was successful and returned proper value
EXPECT_TRUE(callback_resp_pkt6_.get() == adv.get());
// Check that all expected parameters are there
@@ -1611,8 +1614,8 @@ TEST_F(HooksDhcpv6SrvTest, buffer6SendSkip) {
// Check that the callback called is indeed the one we installed
EXPECT_EQ("buffer6_send", callback_name_);
- // Check that there is no packet sent
- EXPECT_EQ(0, srv_->fake_sent_.size());
+ // Check that there is no packet sent.
+ ASSERT_EQ(0, srv_->fake_sent_.size());
// Check if the callout handle state was reset after the callout.
checkCalloutHandleReset(sol);
@@ -1650,7 +1653,7 @@ TEST_F(HooksDhcpv6SrvTest, buffer6SendDrop) {
// This test checks if subnet6_select callout is triggered and reports
// valid parameters
-TEST_F(HooksDhcpv6SrvTest, subnet6Select) {
+TEST_F(HooksDhcpv6SrvTest, subnet6SelectSimple) {
// Configure 2 subnets, both directly reachable over local interface
// (let's not complicate the matter with relays)
@@ -1680,6 +1683,7 @@ TEST_F(HooksDhcpv6SrvTest, subnet6Select) {
comment_ = isc::config::parseAnswer(rcode_, status);
ASSERT_EQ(0, rcode_);
+ // Commit the config
CfgMgr::instance().commit();
// Install subnet6_select_callout
@@ -1722,6 +1726,7 @@ TEST_F(HooksDhcpv6SrvTest, subnet6Select) {
// Server is supposed to report two subnets
ASSERT_EQ(exp_subnets->size(), callback_subnet6collection_->size());
+ ASSERT_GE(exp_subnets->size(), 2);
// Compare that the available subnets are reported as expected
EXPECT_TRUE((*exp_subnets->begin())->get() == (*callback_subnet6collection_->begin())->get());
@@ -2499,9 +2504,9 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRequestPrefix) {
}
// This test verifies that the callout installed on the leases6_committed hook
-// point is executed as a result of REQUEST message sent to reuse an
-// existing lease.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedCache) {
+// point is executed as a result of RENEW message sent to allocate new
+// lease or renew an existing lease.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenew) {
IfaceMgrTestConfig test_config(true);
string config = "{ \"interfaces-config\": {"
@@ -2513,8 +2518,7 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedCache) {
"\"subnet6\": [ { "
" \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
" \"subnet\": \"2001:db8:1::/48\", "
- " \"interface\": \"eth1\", "
- " \"cache-threshold\": .25 "
+ " \"interface\": \"eth1\" "
" } ],"
"\"valid-lifetime\": 4000 }";
@@ -2563,8 +2567,8 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedCache) {
resetCalloutBuffers();
- // Request the lease and make sure that the callout has been executed.
- ASSERT_NO_THROW(client.doRequest());
+ // Renew the lease and make sure that the callout has been executed.
+ ASSERT_NO_THROW(client.doRenew());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -2572,54 +2576,27 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedCache) {
// Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
- // Requested lease should not be present, because it is reused.
+ // Renewed lease should be returned.
ASSERT_TRUE(callback_new_leases6_);
- EXPECT_TRUE(callback_new_leases6_->empty());
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
- // Deleted lease must not be present, because it is renewed.
+ // Deleted lease must not be present, because it is a new allocation.
ASSERT_TRUE(callback_deleted_leases6_);
EXPECT_TRUE(callback_deleted_leases6_->empty());
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
-}
-
-// This test verifies that the callout installed on the leases6_committed hook
-// point is executed as a result of REQUEST message sent to reuse an
-// existing lease. Prefix variant.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedCachePrefix) {
- IfaceMgrTestConfig test_config(true);
-
- string config = "{ \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- "},"
- "\"preferred-lifetime\": 3000,"
- "\"rebind-timer\": 2000, "
- "\"renew-timer\": 1000, "
- "\"subnet6\": [ { "
- " \"pd-pools\": [ {"
- " \"prefix\": \"2001:db8:1::\", "
- " \"prefix-len\": 56, "
- " \"delegated-len\": 64 } ], "
- " \"subnet\": \"2001:db8:1::/48\", "
- " \"interface\": \"eth1\", "
- " \"cache-threshold\": .25 "
- " } ],"
- "\"valid-lifetime\": 4000 }";
-
- Dhcp6Client client;
- client.setInterface("eth1");
- client.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
-
- ASSERT_NO_THROW(configure(config, *client.getServer()));
+ resetCalloutBuffers();
- ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases6_committed", leases6_committed_callout));
+ // Let's try to renew again but force the client to renew a different
+ // address with a different IAID.
+ client.requestAddress(0x2233, IOAddress("2001:db8:1::29"));
- ASSERT_NO_THROW(client.doSARR());
+ ASSERT_NO_THROW(client.doRenew());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -2627,26 +2604,16 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedCachePrefix) {
// Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query6");
- expected_argument_names.push_back("deleted_leases6");
- expected_argument_names.push_back("leases6");
-
- sort(expected_argument_names.begin(), expected_argument_names.end());
- EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
-
- // Newly allocated lease should be returned.
+ // New lease should be returned.
ASSERT_TRUE(callback_new_leases6_);
- ASSERT_EQ(1, callback_new_leases6_->size());
- Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_EQ(2, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(1);
ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
- EXPECT_EQ(64, lease->prefixlen_);
+ EXPECT_EQ("2001:db8:1::29", lease->addr_.toText());
- // Deleted lease must not be present, because it is a new allocation.
+ // The old lease is kept.
ASSERT_TRUE(callback_deleted_leases6_);
- EXPECT_TRUE(callback_deleted_leases6_->empty());
+ ASSERT_TRUE(callback_deleted_leases6_->empty());
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
@@ -2656,8 +2623,10 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedCachePrefix) {
resetCalloutBuffers();
- // Request the lease and make sure that the callout has been executed.
- ASSERT_NO_THROW(client.doRequest());
+ // The renewed address is just a hint.
+ client.requestAddress(0x5577, IOAddress("4000::2"));
+
+ ASSERT_NO_THROW(client.doRenew());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -2665,11 +2634,11 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedCachePrefix) {
// Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
- // Requested lease should not be present, because it is reused.
ASSERT_TRUE(callback_new_leases6_);
- EXPECT_TRUE(callback_new_leases6_->empty());
-
- // Deleted lease must not be present, because it is renewed.
+ EXPECT_EQ(3, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(2);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::", lease->addr_.toText());
ASSERT_TRUE(callback_deleted_leases6_);
EXPECT_TRUE(callback_deleted_leases6_->empty());
@@ -2678,116 +2647,37 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedCachePrefix) {
// Check if the callout handle state was reset after the callout.
checkCalloutHandleReset(client.getContext().query_);
-}
-
-// This test verifies that it is possible to park a packet as a result of
-// the leases6_committed callouts.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRequests) {
- IfaceMgrTestConfig test_config(true);
-
- string config = "{ \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- "},"
- "\"preferred-lifetime\": 3000,"
- "\"rebind-timer\": 2000, "
- "\"renew-timer\": 1000, "
- "\"subnet6\": [ { "
- " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
- " \"subnet\": \"2001:db8:1::/48\", "
- " \"interface\": \"eth1\" "
- " } ],"
- "\"valid-lifetime\": 4000 }";
- // Create first client and perform SARR.
- Dhcp6Client client1;
- client1.setInterface("eth1");
- client1.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+ resetCalloutBuffers();
- ASSERT_NO_THROW(configure(config, *client1.getServer()));
+ // Renew a prefix: this should lead to an error as no prefix pool
+ // is configured.
+ client.requestPrefix(0x1122, 64, IOAddress("2001:db8:1000::"));
- // This callout uses provided IO service object to post a function
- // that unparks the packet. The packet is parked and can be unparked
- // by simply calling IOService::poll.
- ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases6_committed", leases6_committed_park_callout));
+ ASSERT_NO_THROW(client.doRenew());
- ASSERT_NO_THROW(client1.doSARR());
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- // We should be offered an address but the REPLY should not arrive
- // at this point, because the packet is parked.
- ASSERT_FALSE(client1.getContext().response_);
+ // Check the error.
+ EXPECT_EQ(STATUS_NoPrefixAvail, client.getStatusCode(0x1122));
// Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query6");
- expected_argument_names.push_back("deleted_leases6");
- expected_argument_names.push_back("leases6");
-
- sort(expected_argument_names.begin(), expected_argument_names.end());
- EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
-
- // Newly allocated lease should be passed to the callout.
ASSERT_TRUE(callback_new_leases6_);
- ASSERT_EQ(1, callback_new_leases6_->size());
- Lease6Ptr lease = callback_new_leases6_->at(0);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
-
- // Deleted lease must not be present, because it is a new allocation.
+ EXPECT_EQ(3, callback_new_leases6_->size());
ASSERT_TRUE(callback_deleted_leases6_);
EXPECT_TRUE(callback_deleted_leases6_->empty());
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
-
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client1.getContext().query_);
-
- // Reset all indicators because we'll be now creating a second client.
- resetCalloutBuffers();
-
- // Create the second client to test that it may communicate with the
- // server while the previous packet is parked.
- Dhcp6Client client2(client1.getServer());
- client2.setInterface("eth1");
- client2.requestAddress(0xabca, IOAddress("2001:db8:1::29"));
- ASSERT_NO_THROW(client2.doSARR());
-
- // The ADVERTISE should have been returned but not REPLAY, as this
- // packet got parked too.
- ASSERT_FALSE(client2.getContext().response_);
-
- // Check that the callback called is indeed the one we installed.
- EXPECT_EQ("leases6_committed", callback_name_);
-
- // There should be now two actions scheduled on our IO service
- // by the invoked callouts. They unpark both REPLY messages.
- ASSERT_NO_THROW(io_service_->poll());
-
- // Receive and check the first response.
- ASSERT_NO_THROW(client1.receiveResponse());
- ASSERT_TRUE(client1.getContext().response_);
- Pkt6Ptr rsp = client1.getContext().response_;
- EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
- EXPECT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::28")));
-
- // Receive and check the second response.
- ASSERT_NO_THROW(client2.receiveResponse());
- ASSERT_TRUE(client2.getContext().response_);
- rsp = client2.getContext().response_;
- EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
- EXPECT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::29")));
-
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client2.getContext().query_);
+ checkCalloutHandleReset(client.getContext().query_);
}
-// This test verifies that it is possible to park a packet as a result of
-// the leases6_committed callouts. Prefix variant.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRequestsPrefixes) {
+// This test verifies that the callout installed on the leases6_committed hook
+// point is executed as a result of RENEW message sent to allocate new
+// lease or renew an existing lease. Prefix variant.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenewPrefix) {
IfaceMgrTestConfig test_config(true);
string config = "{ \"interfaces-config\": {"
@@ -2806,24 +2696,19 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRequestsPrefixes) {
" } ],"
"\"valid-lifetime\": 4000 }";
- // Create first client and perform SARR.
- Dhcp6Client client1;
- client1.setInterface("eth1");
- client1.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
- ASSERT_NO_THROW(configure(config, *client1.getServer()));
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
- // This callout uses provided IO service object to post a function
- // that unparks the packet. The packet is parked and can be unparked
- // by simply calling IOService::poll.
ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases6_committed", leases6_committed_park_callout));
+ "leases6_committed", leases6_committed_callout));
- ASSERT_NO_THROW(client1.doSARR());
+ ASSERT_NO_THROW(client.doSARR());
- // We should be offered an address but the REPLY should not arrive
- // at this point, because the packet is parked.
- ASSERT_FALSE(client1.getContext().response_);
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
// Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
@@ -2837,7 +2722,7 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRequestsPrefixes) {
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
- // Newly allocated lease should be passed to the callout.
+ // Newly allocated lease should be returned.
ASSERT_TRUE(callback_new_leases6_);
ASSERT_EQ(1, callback_new_leases6_->size());
Lease6Ptr lease = callback_new_leases6_->at(0);
@@ -2852,331 +2737,125 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRequestsPrefixes) {
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client1.getContext().query_);
-
- // Reset all indicators because we'll be now creating a second client.
resetCalloutBuffers();
- // Create the second client to test that it may communicate with the
- // server while the previous packet is parked.
- Dhcp6Client client2(client1.getServer());
- client2.setInterface("eth1");
- client2.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:29::"));
- ASSERT_NO_THROW(client2.doSARR());
+ // Renew the lease and make sure that the callout has been executed.
+ ASSERT_NO_THROW(client.doRenew());
- // The ADVERTISE should have been returned but not REPLAY, as this
- // packet got parked too.
- ASSERT_FALSE(client2.getContext().response_);
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- // Check that the callback called is indeed the one we installed.
+ // Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
- // There should be now two actions scheduled on our IO service
- // by the invoked callouts. They unpark both REPLY messages.
- ASSERT_NO_THROW(io_service_->poll());
+ // Renewed lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
- // Receive and check the first response.
- ASSERT_NO_THROW(client1.receiveResponse());
- ASSERT_TRUE(client1.getContext().response_);
- Pkt6Ptr rsp = client1.getContext().response_;
- EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
- EXPECT_TRUE(client1.hasLeaseForPrefix(IOAddress("2001:db8:1:28::"), 64));
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
- // Receive and check the second response.
- ASSERT_NO_THROW(client2.receiveResponse());
- ASSERT_TRUE(client2.getContext().response_);
- rsp = client2.getContext().response_;
- EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
- EXPECT_TRUE(client2.hasLeaseForPrefix(IOAddress("2001:db8:1:29::"), 64));
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client2.getContext().query_);
-}
-
-// This test verifies that incoming (positive) RENEW can be handled properly,
-// and the lease6_renew callouts are triggered.
-TEST_F(HooksDhcpv6SrvTest, basicLease6Renew) {
- NakedDhcpv6Srv srv(0);
-
- // Install lease6_renew_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_renew", lease6_renew_callout));
-
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
-
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
-
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
-
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
-
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
+ checkCalloutHandleReset(client.getContext().query_);
- // Check that preferred, valid and cltt really set and not using
- // previous (500, 501, etc.) values
- EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
- EXPECT_NE(l->valid_lft_, subnet_->getValid());
- EXPECT_NE(l->cltt_, time(NULL));
+ resetCalloutBuffers();
- // Let's create a RENEW
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- req->setIface("eth0");
- req->setIndex(ETH0_INDEX);
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
+ // Let's try to renew again but force the client to renew a different
+ // prefix with a different IAID.
+ client.requestPrefix(0x2233, 64, IOAddress("2001:db8:1:29::"));
- OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(renewed_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
- // Server-id is mandatory in RENEW
- req->addOption(srv.getServerID());
+ ASSERT_NO_THROW(client.doRenew());
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRenew(req);
- ASSERT_TRUE(reply);
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
// Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease6_renew", callback_name_);
-
- // Check that appropriate parameters are passed to the callouts
- EXPECT_TRUE(callback_qry_pkt6_);
- EXPECT_TRUE(callback_lease6_);
- EXPECT_TRUE(callback_ia_na_);
-
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query6");
- expected_argument_names.push_back("lease6");
- expected_argument_names.push_back("ia_na");
-
- sort(callback_argument_names_.begin(), callback_argument_names_.end());
- sort(expected_argument_names.begin(), expected_argument_names.end());
-
- EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
-
- // Check if we get response at all
- checkResponse(reply, DHCPV6_REPLY, 1234);
-
- OptionPtr tmp = reply->getOption(D6O_IA_NA);
- ASSERT_TRUE(tmp);
-
- // Check that IA_NA was returned and that there's an address included
- boost::shared_ptr<Option6IAAddr> addr_opt;
- ASSERT_NO_FATAL_FAILURE(addr_opt = checkIA_NA(reply, 234, subnet_->getT1(),
- subnet_->getT2()));
-
- ASSERT_TRUE(addr_opt);
- // Check that the lease is really in the database
- l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
- ASSERT_TRUE(l);
+ EXPECT_EQ("leases6_committed", callback_name_);
- // Check that the lease has been returned
- ASSERT_TRUE(callback_lease6_);
+ // New lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(2, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(1);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:29::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
- // Check that the returned lease6 in callout is the same as the one in the
- // database
- EXPECT_TRUE(*callback_lease6_ == *l);
+ // The old lease is kept.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ ASSERT_TRUE(callback_deleted_leases6_->empty());
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(req);
-}
-
-// This test verifies that incoming (positive) RENEW can be handled properly,
-// and the lease6_renew callouts are able to change the lease being updated.
-TEST_F(HooksDhcpv6SrvTest, leaseUpdateLease6Renew) {
- NakedDhcpv6Srv srv(0);
-
- // Install lease6_renew_update
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_renew", lease6_renew_update));
-
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
-
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
-
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
-
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
-
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
-
- // Check that preferred, valid and cltt really set and not using
- // previous (500, 501, etc.) values
- EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
- EXPECT_NE(l->valid_lft_, subnet_->getValid());
- EXPECT_NE(l->cltt_, time(NULL));
-
- // Let's create a RENEW
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- req->setIface("eth0");
- req->setIndex(ETH0_INDEX);
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
-
- OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(renewed_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
-
- // Server-id is mandatory in RENEW
- req->addOption(srv.getServerID());
-
- // Turn on tee time calculation so we can see the effect of overriding
- // the lease life time.
- subnet_->setCalculateTeeTimes(true);
- Triplet<uint32_t> unspecified;
- subnet_->setT1(unspecified);
- subnet_->setT2(unspecified);
- subnet_->setT1Percent(0.60);
- subnet_->setT2Percent(0.80);
-
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRenew(req);
- ASSERT_TRUE(reply);
-
- // Check if we get response at all
- checkResponse(reply, DHCPV6_REPLY, 1234);
+ checkCalloutHandleReset(client.getContext().query_);
- OptionPtr tmp = reply->getOption(D6O_IA_NA);
- ASSERT_TRUE(tmp);
+ resetCalloutBuffers();
- // Check that IA_NA was returned and that there's an address included
- boost::shared_ptr<Option6IAAddr> addr_opt;
- ASSERT_NO_FATAL_FAILURE(addr_opt = checkIA_NA(reply, 1000, 602, 802));
+ // The renewed prefix is just a hint.
+ client.requestPrefix(0x5577, 64, IOAddress("4000::1"));
- ASSERT_TRUE(addr_opt);
- // Check that the lease is really in the database
- l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
- ASSERT_TRUE(l);
+ ASSERT_NO_THROW(client.doRenew());
- // Check that we chose the distinct override values
- ASSERT_NE(override_preferred_, subnet_->getPreferred());
- EXPECT_NE(override_valid_, subnet_->getValid());
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- // Check that preferred, valid were overridden the callout
- EXPECT_EQ(override_preferred_, l->preferred_lft_);
- EXPECT_EQ(override_valid_, l->valid_lft_);
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
- // Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
- int32_t cltt = static_cast<int32_t>(l->cltt_);
- int32_t expected = static_cast<int32_t>(time(NULL));
- // Equality or difference by 1 between cltt and expected is ok.
- EXPECT_GE(1, abs(cltt - expected));
+ ASSERT_TRUE(callback_new_leases6_);
+ EXPECT_EQ(3, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(2);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
- Lease6Ptr deleted_lease =
- LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr_opt->getAddress());
- EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(deleted_lease));
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(req);
-}
-
-// This test verifies that incoming (positive) RENEW can be handled properly,
-// and the lease6_renew callouts are able to set the skip flag that will
-// reject the renewal
-TEST_F(HooksDhcpv6SrvTest, skipLease6Renew) {
- NakedDhcpv6Srv srv(0);
-
- // Install lease6_renew_skip_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_renew", lease6_renew_skip_callout));
-
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
-
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
-
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
-
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
-
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
-
- // Check that preferred, valid and cltt are really set and not using
- // previous (500, 501, etc.) values
- EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
- EXPECT_NE(l->valid_lft_, subnet_->getValid());
- EXPECT_NE(l->cltt_, time(NULL));
+ checkCalloutHandleReset(client.getContext().query_);
- // Let's create a RENEW
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- req->setIface("eth0");
- req->setIndex(ETH0_INDEX);
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
+ resetCalloutBuffers();
- OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(renewed_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
+ // Renew an address: this should lead to an error as no address pool
+ // is configured.
+ client.requestAddress(0x1122, IOAddress("2001:db8:1::28"));
- // Server-id is mandatory in RENEW
- req->addOption(srv.getServerID());
+ ASSERT_NO_THROW(client.doRenew());
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRenew(req);
- ASSERT_TRUE(reply);
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- // Check that our callback was called
- EXPECT_EQ("lease6_renew", callback_name_);
+ // Check the error.
+ EXPECT_EQ(STATUS_NoAddrsAvail, client.getStatusCode(0x1122));
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr);
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
- // Check that the old values are still there and they were not
- // updated by the renewal
- EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
- EXPECT_NE(l->valid_lft_, subnet_->getValid());
- EXPECT_NE(l->cltt_, time(NULL));
+ ASSERT_TRUE(callback_new_leases6_);
+ EXPECT_EQ(3, callback_new_leases6_->size());
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(req);
+ checkCalloutHandleReset(client.getContext().query_);
}
// This test verifies that the callout installed on the leases6_committed hook
-// point is executed as a result of RENEW message sent to allocate new
+// point is executed as a result of REBIND message sent to allocate new
// lease or renew an existing lease.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenew) {
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedRebind) {
IfaceMgrTestConfig test_config(true);
string config = "{ \"interfaces-config\": {"
@@ -3237,8 +2916,8 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenew) {
resetCalloutBuffers();
- // Renew the lease and make sure that the callout has been executed.
- ASSERT_NO_THROW(client.doRenew());
+ // Rebind the lease and make sure that the callout has been executed.
+ ASSERT_NO_THROW(client.doRebind());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -3246,7 +2925,7 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenew) {
// Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
- // Renewed lease should be returned.
+ // Rebound lease should be returned.
ASSERT_TRUE(callback_new_leases6_);
ASSERT_EQ(1, callback_new_leases6_->size());
lease = callback_new_leases6_->at(0);
@@ -3260,13 +2939,16 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenew) {
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client.getContext().query_);
+
resetCalloutBuffers();
- // Let's try to renew again but force the client to renew a different
+ // Let's try to rebind again but force the client to rebind a different
// address with a different IAID.
client.requestAddress(0x2233, IOAddress("2001:db8:1::29"));
- ASSERT_NO_THROW(client.doRenew());
+ ASSERT_NO_THROW(client.doRebind());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -3293,10 +2975,10 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenew) {
resetCalloutBuffers();
- // The renewed address is just a hint.
+ // The rebound address is just a hint.
client.requestAddress(0x5577, IOAddress("4000::2"));
- ASSERT_NO_THROW(client.doRenew());
+ ASSERT_NO_THROW(client.doRebind());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -3320,11 +3002,11 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenew) {
resetCalloutBuffers();
- // Renew a prefix: this should lead to an error as no prefix pool
+ // Rebind a prefix: this should lead to an error as no prefix pool
// is configured.
client.requestPrefix(0x1122, 64, IOAddress("2001:db8:1000::"));
- ASSERT_NO_THROW(client.doRenew());
+ ASSERT_NO_THROW(client.doRebind());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -3345,9 +3027,9 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenew) {
}
// This test verifies that the callout installed on the leases6_committed hook
-// point is executed as a result of RENEW message sent to allocate new
+// point is executed as a result of REBIND message sent to allocate new
// lease or renew an existing lease. Prefix variant.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenewPrefix) {
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedRebindPrefix) {
IfaceMgrTestConfig test_config(true);
string config = "{ \"interfaces-config\": {"
@@ -3407,10 +3089,13 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenewPrefix) {
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client.getContext().query_);
+
resetCalloutBuffers();
- // Renew the lease and make sure that the callout has been executed.
- ASSERT_NO_THROW(client.doRenew());
+ // Rebind the lease and make sure that the callout has been executed.
+ ASSERT_NO_THROW(client.doRebind());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -3418,7 +3103,7 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenewPrefix) {
// Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
- // Renewed lease should be returned.
+ // Rebound lease should be returned.
ASSERT_TRUE(callback_new_leases6_);
ASSERT_EQ(1, callback_new_leases6_->size());
lease = callback_new_leases6_->at(0);
@@ -3438,11 +3123,11 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenewPrefix) {
resetCalloutBuffers();
- // Let's try to renew again but force the client to renew a different
+ // Let's try to rebind again but force the client to rebind a different
// prefix with a different IAID.
client.requestPrefix(0x2233, 64, IOAddress("2001:db8:1:29::"));
- ASSERT_NO_THROW(client.doRenew());
+ ASSERT_NO_THROW(client.doRebind());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -3470,10 +3155,10 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenewPrefix) {
resetCalloutBuffers();
- // The renewed prefix is just a hint.
+ // The rebound prefix is just a hint.
client.requestPrefix(0x5577, 64, IOAddress("4000::1"));
- ASSERT_NO_THROW(client.doRenew());
+ ASSERT_NO_THROW(client.doRebind());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -3498,11 +3183,11 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenewPrefix) {
resetCalloutBuffers();
- // Renew an address: this should lead to an error as no address pool
+ // Rebind an address: this should lead to an error as no address pool
// is configured.
client.requestAddress(0x1122, IOAddress("2001:db8:1::28"));
- ASSERT_NO_THROW(client.doRenew());
+ ASSERT_NO_THROW(client.doRebind());
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -3522,308 +3207,136 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenewPrefix) {
checkCalloutHandleReset(client.getContext().query_);
}
-// This test verifies that incoming (positive) RELEASE can be handled properly,
-// that a REPLY is generated, that the response has status code and that the
-// lease is indeed removed from the database.
-//
-// expected:
-// - returned REPLY message has copy of client-id
-// - returned REPLY message has server-id
-// - returned REPLY message has IA that does not include an IAADDR
-// - lease is actually removed from LeaseMgr
-TEST_F(HooksDhcpv6SrvTest, basicLease6Release) {
- NakedDhcpv6Srv srv(0);
-
- // Install lease6_release_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_release", lease6_release_callout));
-
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
-
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
-
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
+// This test verifies that the leases6_committed callout is executed
+// when DECLINE is processed. The declined lease is expected to be passed
+// in leases6 argument to the callout.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedDecline) {
+ IfaceMgrTestConfig test_config(true);
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
- // Let's create a RELEASE
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
- OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(released_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
- // Server-id is mandatory in RELEASE
- req->addOption(srv.getServerID());
+ ASSERT_NO_THROW(client.doSARR());
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRelease(req);
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- ASSERT_TRUE(reply);
+ ASSERT_NO_THROW(client.doDecline());
// Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease6_release", callback_name_);
-
- // Check that appropriate parameters are passed to the callouts
- EXPECT_TRUE(callback_qry_pkt6_);
- EXPECT_TRUE(callback_lease6_);
+ EXPECT_EQ("leases6_committed", callback_name_);
// Check if all expected parameters were really received
vector<string> expected_argument_names;
expected_argument_names.push_back("query6");
- expected_argument_names.push_back("lease6");
- sort(callback_argument_names_.begin(), callback_argument_names_.end());
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
- // Check that the lease is really gone in the database
- // get lease by address
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr);
- ASSERT_FALSE(l);
+ // No deleted leases.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ ASSERT_TRUE(callback_deleted_leases6_->empty());
- // Get lease by subnetid/duid/iaid combination
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
- subnet_->getID());
- ASSERT_FALSE(l);
+ // Declined lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(req);
+ checkCalloutHandleReset(client.getContext().query_);
}
-// This is a variant of the previous test that tests that callouts are
-// properly invoked for the prefix release case.
-TEST_F(HooksDhcpv6SrvTest, basicLease6ReleasePD) {
- NakedDhcpv6Srv srv(0);
-
- // Install lease6_release_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_release", lease6_release_callout));
-
- const IOAddress prefix("2001:db8:1:2:1::");
- const uint32_t iaid = 234;
-
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
-
- // Check that the prefix we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_PD, prefix));
-
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_PD, prefix, duid_, iaid,
- 501, 502, subnet_->getID(),
- HWAddrPtr(), 80));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+// This test verifies that the leases6_committed callout is executed
+// when DECLINE is processed. Variant with 2 IA_NAs.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedDeclineTwoNAs) {
+ IfaceMgrTestConfig test_config(true);
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD,
- prefix);
- ASSERT_TRUE(l);
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
- // Let's create a RELEASE
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_PD, iaid, 1500, 3000);
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+ client.requestAddress(0x2233, IOAddress("2001:db8:1::29"));
- OptionPtr released_addr_opt(new Option6IAPrefix(D6O_IAPREFIX, prefix, 80,
- 300, 500));
- ia->addOption(released_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
- // Server-id is mandatory in RELEASE
- req->addOption(srv.getServerID());
+ ASSERT_NO_THROW(client.doSARR());
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRelease(req);
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
- ASSERT_TRUE(reply);
+ ASSERT_NO_THROW(client.doDecline());
// Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease6_release", callback_name_);
-
- // Check that appropriate parameters are passed to the callouts
- EXPECT_TRUE(callback_qry_pkt6_);
- EXPECT_TRUE(callback_lease6_);
+ EXPECT_EQ("leases6_committed", callback_name_);
// Check if all expected parameters were really received
vector<string> expected_argument_names;
expected_argument_names.push_back("query6");
- expected_argument_names.push_back("lease6");
- sort(callback_argument_names_.begin(), callback_argument_names_.end());
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
- // Check that the lease is really gone in the database
- // get lease by address
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD, prefix);
- ASSERT_FALSE(l);
+ // No deleted leases.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ ASSERT_TRUE(callback_deleted_leases6_->empty());
- // Get lease by subnetid/duid/iaid combination
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD, *duid_, iaid,
- subnet_->getID());
- ASSERT_FALSE(l);
+ // Declined lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(2, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+ lease = callback_new_leases6_->at(1);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::29", lease->addr_.toText());
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(req);
-}
-
-// This test verifies that skip flag returned by a callout installed on the
-// lease6_release hook point will keep the lease.
-TEST_F(HooksDhcpv6SrvTest, skipLease6Release) {
- NakedDhcpv6Srv srv(0);
-
- // Install lease6_release_skip
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_release", lease6_release_skip));
-
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
-
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
-
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
-
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
-
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
-
- // Let's create a RELEASE
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
-
- OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(released_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
-
- // Server-id is mandatory in RELEASE
- req->addOption(srv.getServerID());
-
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRelease(req);
-
- ASSERT_TRUE(reply);
-
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease6_release", callback_name_);
-
- // Check that the lease is still there
- // get lease by address
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
-
- // Get lease by subnetid/duid/iaid combination
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
- subnet_->getID());
- ASSERT_TRUE(l);
-
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(req);
-}
-
-// This test verifies that drop flag returned by a callout installed on the
-// lease6_release hook point will keep the lease.
-TEST_F(HooksDhcpv6SrvTest, dropLease6Release) {
- NakedDhcpv6Srv srv(0);
-
- // Install lease6_release_drop
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_release", lease6_release_drop));
-
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
-
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
-
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
-
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
-
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
-
- // Let's create a RELEASE
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
-
- OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(released_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
-
- // Server-id is mandatory in RELEASE
- req->addOption(srv.getServerID());
-
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRelease(req);
-
- ASSERT_TRUE(reply);
-
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease6_release", callback_name_);
-
- // Check that the lease is still there
- // get lease by address
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
-
- // Get lease by subnetid/duid/iaid combination
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
- subnet_->getID());
- ASSERT_TRUE(l);
-
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(req);
+ checkCalloutHandleReset(client.getContext().query_);
}
// This test verifies that the leases6_committed callout is executed
@@ -3850,13 +3363,14 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedRelease) {
ASSERT_NO_THROW(configure(config, *client.getServer()));
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
+
ASSERT_NO_THROW(client.doSARR());
+
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
- ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases6_committed", leases6_committed_callout));
-
ASSERT_NO_THROW(client.doRelease());
// Check that the callback called is indeed the one we installed
@@ -3917,6 +3431,7 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedReleasePrefix) {
ASSERT_NO_THROW(configure(config, *client.getServer()));
ASSERT_NO_THROW(client.doSARR());
+
// Make sure that we received a response
ASSERT_TRUE(client.getContext().response_);
@@ -4026,9 +3541,684 @@ TEST_F(HooksDhcpv6SrvTest, leases6CommittedReleaseMultiple) {
checkCalloutHandleReset(client.getContext().query_);
}
+// This test verifies that the callout installed on the leases6_committed hook
+// point is executed as a result of REQUEST message sent to reuse an
+// existing lease.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedCache) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\", "
+ " \"cache-threshold\": .25 "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
+
+ ASSERT_NO_THROW(client.doSARR());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client.getContext().query_);
+
+ resetCalloutBuffers();
+
+ // Request the lease and make sure that the callout has been executed.
+ ASSERT_NO_THROW(client.doRequest());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Requested lease should not be present, because it is reused.
+ ASSERT_TRUE(callback_new_leases6_);
+ EXPECT_TRUE(callback_new_leases6_->empty());
+
+ // Deleted lease must not be present, because it is renewed.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client.getContext().query_);
+}
+
+// This test verifies that the callout installed on the leases6_committed hook
+// point is executed as a result of REQUEST message sent to reuse an
+// existing lease. Prefix variant.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedCachePrefix) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pd-pools\": [ {"
+ " \"prefix\": \"2001:db8:1::\", "
+ " \"prefix-len\": 56, "
+ " \"delegated-len\": 64 } ], "
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\", "
+ " \"cache-threshold\": .25 "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
+
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
+
+ ASSERT_NO_THROW(client.doSARR());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client.getContext().query_);
+
+ resetCalloutBuffers();
+
+ // Request the lease and make sure that the callout has been executed.
+ ASSERT_NO_THROW(client.doRequest());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Requested lease should not be present, because it is reused.
+ ASSERT_TRUE(callback_new_leases6_);
+ EXPECT_TRUE(callback_new_leases6_->empty());
+
+ // Deleted lease must not be present, because it is renewed.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client.getContext().query_);
+}
+
+// This test verifies that it is possible to park a packet as a result of
+// the leases6_committed callouts.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRequests) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ // Create first client and perform SARR.
+ Dhcp6Client client1;
+ client1.setInterface("eth1");
+ client1.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+
+ ASSERT_NO_THROW(configure(config, *client1.getServer()));
+
+ // This callout uses provided IO service object to post a function
+ // that unparks the packet. The packet is parked and can be unparked
+ // by simply calling IOService::poll.
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_park_callout));
+
+ ASSERT_NO_THROW(client1.doSARR());
+
+ // We should be offered an address but the REPLY should not arrive
+ // at this point, because the packet is parked.
+ ASSERT_FALSE(client1.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be passed to the callout.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client1.getContext().query_);
+
+ // Reset all indicators because we'll be now creating a second client.
+ resetCalloutBuffers();
+
+ // Create the second client to test that it may communicate with the
+ // server while the previous packet is parked.
+ Dhcp6Client client2(client1.getServer());
+ client2.setInterface("eth1");
+ client2.requestAddress(0xabca, IOAddress("2001:db8:1::29"));
+ ASSERT_NO_THROW(client2.doSARR());
+
+ // The ADVERTISE should have been returned but not REPLAY, as this
+ // packet got parked too.
+ ASSERT_FALSE(client2.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed.
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // There should be now two actions scheduled on our IO service
+ // by the invoked callouts. They unpark both REPLY messages.
+ ASSERT_NO_THROW(io_service_->poll());
+
+ // Receive and check the first response.
+ ASSERT_NO_THROW(client1.receiveResponse());
+ ASSERT_TRUE(client1.getContext().response_);
+ Pkt6Ptr rsp = client1.getContext().response_;
+ EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
+ EXPECT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::28")));
+
+ // Receive and check the second response.
+ ASSERT_NO_THROW(client2.receiveResponse());
+ ASSERT_TRUE(client2.getContext().response_);
+ rsp = client2.getContext().response_;
+ EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
+ EXPECT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::29")));
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client2.getContext().query_);
+}
+
+// This test verifies that it is possible to park a packet as a result of
+// the leases6_committed callouts. Prefix variant.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRequestsPrefixes) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pd-pools\": [ {"
+ " \"prefix\": \"2001:db8:1::\", "
+ " \"prefix-len\": 56, "
+ " \"delegated-len\": 64 } ], "
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ // Create first client and perform SARR.
+ Dhcp6Client client1;
+ client1.setInterface("eth1");
+ client1.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
+
+ ASSERT_NO_THROW(configure(config, *client1.getServer()));
+
+ // This callout uses provided IO service object to post a function
+ // that unparks the packet. The packet is parked and can be unparked
+ // by simply calling IOService::poll.
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_park_callout));
+
+ ASSERT_NO_THROW(client1.doSARR());
+
+ // We should be offered an address but the REPLY should not arrive
+ // at this point, because the packet is parked.
+ ASSERT_FALSE(client1.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be passed to the callout.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client1.getContext().query_);
+
+ // Reset all indicators because we'll be now creating a second client.
+ resetCalloutBuffers();
+
+ // Create the second client to test that it may communicate with the
+ // server while the previous packet is parked.
+ Dhcp6Client client2(client1.getServer());
+ client2.setInterface("eth1");
+ client2.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:29::"));
+ ASSERT_NO_THROW(client2.doSARR());
+
+ // The ADVERTISE should have been returned but not REPLAY, as this
+ // packet got parked too.
+ ASSERT_FALSE(client2.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed.
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // There should be now two actions scheduled on our IO service
+ // by the invoked callouts. They unpark both REPLY messages.
+ ASSERT_NO_THROW(io_service_->poll());
+
+ // Receive and check the first response.
+ ASSERT_NO_THROW(client1.receiveResponse());
+ ASSERT_TRUE(client1.getContext().response_);
+ Pkt6Ptr rsp = client1.getContext().response_;
+ EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
+ EXPECT_TRUE(client1.hasLeaseForPrefix(IOAddress("2001:db8:1:28::"), 64));
+
+ // Receive and check the second response.
+ ASSERT_NO_THROW(client2.receiveResponse());
+ ASSERT_TRUE(client2.getContext().response_);
+ rsp = client2.getContext().response_;
+ EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
+ EXPECT_TRUE(client2.hasLeaseForPrefix(IOAddress("2001:db8:1:29::"), 64));
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client2.getContext().query_);
+}
+
+// This test verifies that incoming (positive) RENEW can be handled properly,
+// and the lease6_renew callouts are triggered.
+TEST_F(HooksDhcpv6SrvTest, lease6RenewSimple) {
+ NakedDhcpv6Srv srv(0);
+
+ // Install lease6_renew_callout
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_renew", lease6_renew_callout));
+
+ const IOAddress addr("2001:db8:1:1::cafe:babe");
+ const uint32_t iaid = 234;
+
+ // Generate client-id also duid_
+ OptionPtr clientid = generateClientId();
+
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
+
+ // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+ // value on purpose. They should be updated during RENEW.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
+ 501, 502, subnet_->getID(),
+ HWAddrPtr(), 0));
+ lease->cltt_ = 1234;
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Check that the lease is really in the database
+ Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr);
+ ASSERT_TRUE(l);
+
+ // Check that preferred, valid and cltt really set and not using
+ // previous (500, 501, etc.) values
+ EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
+ EXPECT_NE(l->valid_lft_, subnet_->getValid());
+ EXPECT_NE(l->cltt_, time(NULL));
+
+ // Let's create a RENEW
+ Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
+ req->setRemoteAddr(IOAddress("fe80::abcd"));
+ req->setIface("eth0");
+ req->setIndex(ETH0_INDEX);
+ boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
+
+ OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+ ia->addOption(renewed_addr_opt);
+ req->addOption(ia);
+ req->addOption(clientid);
+ // Server-id is mandatory in RENEW
+ req->addOption(srv.getServerID());
+
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRenew(req);
+ ASSERT_TRUE(reply);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("lease6_renew", callback_name_);
+
+ // Check that appropriate parameters are passed to the callouts
+ EXPECT_TRUE(callback_qry_pkt6_);
+ EXPECT_TRUE(callback_lease6_);
+ EXPECT_TRUE(callback_ia_na_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("lease6");
+ expected_argument_names.push_back("ia_na");
+
+ sort(callback_argument_names_.begin(), callback_argument_names_.end());
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Check if we get response at all
+ checkResponse(reply, DHCPV6_REPLY, 1234);
+
+ OptionPtr tmp = reply->getOption(D6O_IA_NA);
+ ASSERT_TRUE(tmp);
+
+ // Check that IA_NA was returned and that there's an address included
+ boost::shared_ptr<Option6IAAddr> addr_opt;
+ ASSERT_NO_FATAL_FAILURE(addr_opt = checkIA_NA(reply, 234, subnet_->getT1(),
+ subnet_->getT2()));
+
+ ASSERT_TRUE(addr_opt);
+ // Check that the lease is really in the database
+ l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
+ ASSERT_TRUE(l);
+
+ // Check that the lease has been returned
+ ASSERT_TRUE(callback_lease6_);
+
+ // Check that the returned lease6 in callout is the same as the one in the
+ // database
+ EXPECT_TRUE(*callback_lease6_ == *l);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(req);
+}
+
+// This test verifies that incoming (positive) RENEW can be handled properly,
+// and the lease6_renew callouts are able to change the lease being updated.
+TEST_F(HooksDhcpv6SrvTest, lease6RenewLeaseUpdate) {
+ NakedDhcpv6Srv srv(0);
+
+ // Install lease6_renew_update
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_renew", lease6_renew_update));
+
+ const IOAddress addr("2001:db8:1:1::cafe:babe");
+ const uint32_t iaid = 234;
+
+ // Generate client-id also duid_
+ OptionPtr clientid = generateClientId();
+
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
+
+ // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+ // value on purpose. They should be updated during RENEW.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
+ 501, 502, subnet_->getID(),
+ HWAddrPtr(), 0));
+ lease->cltt_ = 1234;
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Check that the lease is really in the database
+ Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr);
+ ASSERT_TRUE(l);
+
+ // Check that preferred, valid and cltt really set and not using
+ // previous (500, 501, etc.) values
+ EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
+ EXPECT_NE(l->valid_lft_, subnet_->getValid());
+ EXPECT_NE(l->cltt_, time(NULL));
+
+ // Let's create a RENEW
+ Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
+ req->setRemoteAddr(IOAddress("fe80::abcd"));
+ req->setIface("eth0");
+ req->setIndex(ETH0_INDEX);
+ boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
+
+ OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+ ia->addOption(renewed_addr_opt);
+ req->addOption(ia);
+ req->addOption(clientid);
+
+ // Server-id is mandatory in RENEW
+ req->addOption(srv.getServerID());
+
+ // Turn on tee time calculation so we can see the effect of overriding
+ // the lease life time.
+ subnet_->setCalculateTeeTimes(true);
+ Triplet<uint32_t> unspecified;
+ subnet_->setT1(unspecified);
+ subnet_->setT2(unspecified);
+ subnet_->setT1Percent(0.60);
+ subnet_->setT2Percent(0.80);
+
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRenew(req);
+ ASSERT_TRUE(reply);
+
+ // Check if we get response at all
+ checkResponse(reply, DHCPV6_REPLY, 1234);
+
+ OptionPtr tmp = reply->getOption(D6O_IA_NA);
+ ASSERT_TRUE(tmp);
+
+ // Check that IA_NA was returned and that there's an address included
+ boost::shared_ptr<Option6IAAddr> addr_opt;
+ ASSERT_NO_FATAL_FAILURE(addr_opt = checkIA_NA(reply, 1000, 602, 802));
+
+ ASSERT_TRUE(addr_opt);
+ // Check that the lease is really in the database
+ l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
+ ASSERT_TRUE(l);
+
+ // Check that we chose the distinct override values
+ ASSERT_NE(override_preferred_, subnet_->getPreferred());
+ EXPECT_NE(override_valid_, subnet_->getValid());
+
+ // Check that preferred, valid were overridden the callout
+ EXPECT_EQ(override_preferred_, l->preferred_lft_);
+ EXPECT_EQ(override_valid_, l->valid_lft_);
+
+ // Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
+ int32_t cltt = static_cast<int32_t>(l->cltt_);
+ int32_t expected = static_cast<int32_t>(time(NULL));
+ // Equality or difference by 1 between cltt and expected is ok.
+ EXPECT_GE(1, abs(cltt - expected));
+
+ Lease6Ptr deleted_lease =
+ LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr_opt->getAddress());
+ EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(deleted_lease));
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(req);
+}
+
+// This test verifies that incoming (positive) RENEW can be handled properly,
+// and the lease6_renew callouts are able to set the skip flag that will
+// reject the renewal
+TEST_F(HooksDhcpv6SrvTest, lease6RenewSkip) {
+ NakedDhcpv6Srv srv(0);
+
+ // Install lease6_renew_skip_callout
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_renew", lease6_renew_skip_callout));
+
+ const IOAddress addr("2001:db8:1:1::cafe:babe");
+ const uint32_t iaid = 234;
+
+ // Generate client-id also duid_
+ OptionPtr clientid = generateClientId();
+
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
+
+ // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+ // value on purpose. They should be updated during RENEW.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
+ 501, 502, subnet_->getID(),
+ HWAddrPtr(), 0));
+ lease->cltt_ = 1234;
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Check that the lease is really in the database
+ Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr);
+ ASSERT_TRUE(l);
+
+ // Check that preferred, valid and cltt are really set and not using
+ // previous (500, 501, etc.) values
+ EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
+ EXPECT_NE(l->valid_lft_, subnet_->getValid());
+ EXPECT_NE(l->cltt_, time(NULL));
+
+ // Let's create a RENEW
+ Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
+ req->setRemoteAddr(IOAddress("fe80::abcd"));
+ req->setIface("eth0");
+ req->setIndex(ETH0_INDEX);
+ boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
+
+ OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+ ia->addOption(renewed_addr_opt);
+ req->addOption(ia);
+ req->addOption(clientid);
+
+ // Server-id is mandatory in RENEW
+ req->addOption(srv.getServerID());
+
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRenew(req);
+ ASSERT_TRUE(reply);
+
+ // Check that our callback was called
+ EXPECT_EQ("lease6_renew", callback_name_);
+
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr);
+
+ // Check that the old values are still there and they were not
+ // updated by the renewal
+ EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
+ EXPECT_NE(l->valid_lft_, subnet_->getValid());
+ EXPECT_NE(l->cltt_, time(NULL));
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(req);
+}
+
// This test verifies that incoming (positive) REBIND can be handled properly,
// and the lease6_rebind callouts are triggered.
-TEST_F(HooksDhcpv6SrvTest, basicLease6Rebind) {
+TEST_F(HooksDhcpv6SrvTest, lease6RebindSimple) {
NakedDhcpv6Srv srv(0);
// Install lease6_rebind_callout
@@ -4127,7 +4317,7 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Rebind) {
// This test verifies that incoming (positive) REBIND can be handled properly,
// and the lease6_rebind callouts are able to change the lease being updated.
-TEST_F(HooksDhcpv6SrvTest, leaseUpdateLease6Rebind) {
+TEST_F(HooksDhcpv6SrvTest, lease6RebindLeaseUpdate) {
NakedDhcpv6Srv srv(0);
// Install lease6_rebind_update
@@ -4229,7 +4419,7 @@ TEST_F(HooksDhcpv6SrvTest, leaseUpdateLease6Rebind) {
// This test verifies that incoming (positive) REBIND can be handled properly,
// and the lease6_rebind callouts are able to set the skip flag that will
// reject the rebinding
-TEST_F(HooksDhcpv6SrvTest, skipLease6Rebind) {
+TEST_F(HooksDhcpv6SrvTest, lease6RebindSkip) {
NakedDhcpv6Srv srv(0);
// Install lease6_rebind_skip
@@ -4295,364 +4485,495 @@ TEST_F(HooksDhcpv6SrvTest, skipLease6Rebind) {
checkCalloutHandleReset(req);
}
-// This test verifies that the callout installed on the leases6_committed hook
-// point is executed as a result of REBIND message sent to allocate new
-// lease or renew an existing lease.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedRebind) {
- IfaceMgrTestConfig test_config(true);
+// This test verifies that incoming (positive) RELEASE can be handled properly,
+// that a REPLY is generated, that the response has status code and that the
+// lease is indeed removed from the database.
+//
+// expected:
+// - returned REPLY message has copy of client-id
+// - returned REPLY message has server-id
+// - returned REPLY message has IA that does not include an IAADDR
+// - lease is actually removed from LeaseMgr
+TEST_F(HooksDhcpv6SrvTest, lease6ReleaseSimple) {
+ NakedDhcpv6Srv srv(0);
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setFlushReclaimedTimerWaitTime(0);
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setHoldReclaimedTime(0);
- string config = "{ \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- "},"
- "\"preferred-lifetime\": 3000,"
- "\"rebind-timer\": 2000, "
- "\"renew-timer\": 1000, "
- "\"subnet6\": [ { "
- " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
- " \"subnet\": \"2001:db8:1::/48\", "
- " \"interface\": \"eth1\" "
- " } ],"
- "\"valid-lifetime\": 4000 }";
+ // Install lease6_release_callout
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_release", lease6_release_callout));
- Dhcp6Client client;
- client.setInterface("eth1");
- client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+ const IOAddress addr("2001:db8:1:1::cafe:babe");
+ const uint32_t iaid = 234;
- ASSERT_NO_THROW(configure(config, *client.getServer()));
+ // Generate client-id also duid_
+ OptionPtr clientid = generateClientId();
- ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases6_committed", leases6_committed_callout));
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
- ASSERT_NO_THROW(client.doSARR());
+ // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+ // value on purpose. They should be updated during RENEW.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
+ 501, 502, subnet_->getID(),
+ HWAddrPtr(), 0));
+ lease->cltt_ = 1234;
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ // Check that the lease is really in the database
+ Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr);
+ ASSERT_TRUE(l);
+
+ // Let's create a RELEASE
+ Pkt6Ptr rel = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
+ rel->setRemoteAddr(IOAddress("fe80::abcd"));
+ boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
+
+ OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+ ia->addOption(released_addr_opt);
+ rel->addOption(ia);
+ rel->addOption(clientid);
+
+ // Server-id is mandatory in RELEASE
+ rel->addOption(srv.getServerID());
+
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRelease(rel);
+
+ ASSERT_TRUE(reply);
// Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
+ EXPECT_EQ("lease6_release", callback_name_);
+
+ // Check that appropriate parameters are passed to the callouts
+ EXPECT_TRUE(callback_qry_pkt6_);
+ EXPECT_TRUE(callback_lease6_);
// Check if all expected parameters were really received
vector<string> expected_argument_names;
expected_argument_names.push_back("query6");
- expected_argument_names.push_back("deleted_leases6");
- expected_argument_names.push_back("leases6");
-
+ expected_argument_names.push_back("lease6");
+ sort(callback_argument_names_.begin(), callback_argument_names_.end());
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
- // Newly allocated lease should be returned.
- ASSERT_TRUE(callback_new_leases6_);
- ASSERT_EQ(1, callback_new_leases6_->size());
- Lease6Ptr lease = callback_new_leases6_->at(0);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+ // Check that the lease is really gone in the database
+ // get lease by address
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr);
+ ASSERT_FALSE(l);
- // Deleted lease must not be present, because it is a new allocation.
- ASSERT_TRUE(callback_deleted_leases6_);
- EXPECT_TRUE(callback_deleted_leases6_->empty());
+ // Get lease by subnetid/duid/iaid combination
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
+ subnet_->getID());
+ ASSERT_FALSE(l);
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
+ checkCalloutHandleReset(rel);
+}
- resetCalloutBuffers();
+// This test verifies that incoming (positive) RELEASE can be handled properly,
+// that a REPLY is generated, that the response has status code and that the
+// lease is indeed removed from the database.
+//
+// expected:
+// - returned REPLY message has copy of client-id
+// - returned REPLY message has server-id
+// - returned REPLY message has IA that does not include an IAADDR
+// - lease is actually removed from LeaseMgr
+TEST_F(HooksDhcpv6SrvTest, lease6ReleaseSimpleNoDelete) {
+ NakedDhcpv6Srv srv(0);
- // Rebind the lease and make sure that the callout has been executed.
- ASSERT_NO_THROW(client.doRebind());
+ // Install lease6_release_callout
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_release", lease6_release_callout));
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ const IOAddress addr("2001:db8:1:1::cafe:babe");
+ const uint32_t iaid = 234;
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
+ // Generate client-id also duid_
+ OptionPtr clientid = generateClientId();
- // Rebound lease should be returned.
- ASSERT_TRUE(callback_new_leases6_);
- ASSERT_EQ(1, callback_new_leases6_->size());
- lease = callback_new_leases6_->at(0);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
- // Deleted lease must not be present, because it is a new allocation.
- ASSERT_TRUE(callback_deleted_leases6_);
- EXPECT_TRUE(callback_deleted_leases6_->empty());
+ // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+ // value on purpose. They should be updated during RENEW.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
+ 501, 502, subnet_->getID(),
+ HWAddrPtr(), 0));
+ lease->cltt_ = 1234;
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
+ // Check that the lease is really in the database
+ Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr);
+ ASSERT_TRUE(l);
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
+ // Let's create a RELEASE
+ Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
+ req->setRemoteAddr(IOAddress("fe80::abcd"));
+ boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
- resetCalloutBuffers();
+ OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+ ia->addOption(released_addr_opt);
+ req->addOption(ia);
+ req->addOption(clientid);
- // Let's try to rebind again but force the client to rebind a different
- // address with a different IAID.
- client.requestAddress(0x2233, IOAddress("2001:db8:1::29"));
+ // Server-id is mandatory in RELEASE
+ req->addOption(srv.getServerID());
- ASSERT_NO_THROW(client.doRebind());
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRelease(req);
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ ASSERT_TRUE(reply);
// Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
+ EXPECT_EQ("lease6_release", callback_name_);
- // New lease should be returned.
- ASSERT_TRUE(callback_new_leases6_);
- ASSERT_EQ(2, callback_new_leases6_->size());
- lease = callback_new_leases6_->at(1);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::29", lease->addr_.toText());
+ // Check that appropriate parameters are passed to the callouts
+ EXPECT_TRUE(callback_qry_pkt6_);
+ EXPECT_TRUE(callback_lease6_);
- // The old lease is kept.
- ASSERT_TRUE(callback_deleted_leases6_);
- ASSERT_TRUE(callback_deleted_leases6_->empty());
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("lease6");
+ sort(callback_argument_names_.begin(), callback_argument_names_.end());
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Check that the lease is not gone in the database
+ // get lease by address
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr);
+ ASSERT_TRUE(l);
+
+ EXPECT_TRUE(l->expired());
+
+ // Get lease by subnetid/duid/iaid combination
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
+ subnet_->getID());
+ ASSERT_TRUE(l);
+
+ EXPECT_TRUE(l->expired());
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
-
- resetCalloutBuffers();
+ checkCalloutHandleReset(req);
+}
- // The rebound address is just a hint.
- client.requestAddress(0x5577, IOAddress("4000::2"));
+// This is a variant of the previous test that tests that callouts are
+// properly invoked for the prefix release case.
+TEST_F(HooksDhcpv6SrvTest, lease6ReleasePrefixSimple) {
+ NakedDhcpv6Srv srv(0);
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setFlushReclaimedTimerWaitTime(0);
+ CfgMgr::instance().getCurrentCfg()->getCfgExpiration()->setHoldReclaimedTime(0);
- ASSERT_NO_THROW(client.doRebind());
+ // Install lease6_release_callout
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_release", lease6_release_callout));
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ const IOAddress prefix("2001:db8:1:2:1::");
+ const uint32_t iaid = 234;
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
+ // Generate client-id also duid_
+ OptionPtr clientid = generateClientId();
- ASSERT_TRUE(callback_new_leases6_);
- EXPECT_EQ(3, callback_new_leases6_->size());
- lease = callback_new_leases6_->at(2);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::", lease->addr_.toText());
- ASSERT_TRUE(callback_deleted_leases6_);
- EXPECT_TRUE(callback_deleted_leases6_->empty());
+ // Check that the prefix we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_PD, prefix));
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
+ // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+ // value on purpose. They should be updated during RENEW.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_PD, prefix, duid_, iaid,
+ 501, 502, subnet_->getID(),
+ HWAddrPtr(), 80));
+ lease->cltt_ = 1234;
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
+ // Check that the lease is really in the database
+ Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD,
+ prefix);
+ ASSERT_TRUE(l);
- resetCalloutBuffers();
+ // Let's create a RELEASE
+ Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
+ req->setRemoteAddr(IOAddress("fe80::abcd"));
+ boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_PD, iaid, 1500, 3000);
- // Rebind a prefix: this should lead to an error as no prefix pool
- // is configured.
- client.requestPrefix(0x1122, 64, IOAddress("2001:db8:1000::"));
+ OptionPtr released_addr_opt(new Option6IAPrefix(D6O_IAPREFIX, prefix, 80,
+ 300, 500));
+ ia->addOption(released_addr_opt);
+ req->addOption(ia);
+ req->addOption(clientid);
- ASSERT_NO_THROW(client.doRebind());
+ // Server-id is mandatory in RELEASE
+ req->addOption(srv.getServerID());
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRelease(req);
- // Check the error.
- EXPECT_EQ(STATUS_NoPrefixAvail, client.getStatusCode(0x1122));
+ ASSERT_TRUE(reply);
// Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
+ EXPECT_EQ("lease6_release", callback_name_);
- ASSERT_TRUE(callback_new_leases6_);
- EXPECT_EQ(3, callback_new_leases6_->size());
- ASSERT_TRUE(callback_deleted_leases6_);
- EXPECT_TRUE(callback_deleted_leases6_->empty());
+ // Check that appropriate parameters are passed to the callouts
+ EXPECT_TRUE(callback_qry_pkt6_);
+ EXPECT_TRUE(callback_lease6_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("lease6");
+ sort(callback_argument_names_.begin(), callback_argument_names_.end());
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Check that the lease is really gone in the database
+ // get lease by address
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD, prefix);
+ ASSERT_FALSE(l);
+
+ // Get lease by subnetid/duid/iaid combination
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD, *duid_, iaid,
+ subnet_->getID());
+ ASSERT_FALSE(l);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
+ checkCalloutHandleReset(req);
}
-// This test verifies that the callout installed on the leases6_committed hook
-// point is executed as a result of REBIND message sent to allocate new
-// lease or renew an existing lease. Prefix variant.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedRebindPrefix) {
- IfaceMgrTestConfig test_config(true);
+// This is a variant of the previous test that tests that callouts are
+// properly invoked for the prefix release case.
+TEST_F(HooksDhcpv6SrvTest, lease6ReleasePrefixSimpleNoDelete) {
+ NakedDhcpv6Srv srv(0);
- string config = "{ \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- "},"
- "\"preferred-lifetime\": 3000,"
- "\"rebind-timer\": 2000, "
- "\"renew-timer\": 1000, "
- "\"subnet6\": [ { "
- " \"pd-pools\": [ {"
- " \"prefix\": \"2001:db8:1::\", "
- " \"prefix-len\": 56, "
- " \"delegated-len\": 64 } ], "
- " \"subnet\": \"2001:db8:1::/48\", "
- " \"interface\": \"eth1\" "
- " } ],"
- "\"valid-lifetime\": 4000 }";
+ // Install lease6_release_callout
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_release", lease6_release_callout));
- Dhcp6Client client;
- client.setInterface("eth1");
- client.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
+ const IOAddress prefix("2001:db8:1:2:1::");
+ const uint32_t iaid = 234;
- ASSERT_NO_THROW(configure(config, *client.getServer()));
+ // Generate client-id also duid_
+ OptionPtr clientid = generateClientId();
- ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases6_committed", leases6_committed_callout));
+ // Check that the prefix we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_PD, prefix));
- ASSERT_NO_THROW(client.doSARR());
+ // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+ // value on purpose. They should be updated during RENEW.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_PD, prefix, duid_, iaid,
+ 501, 502, subnet_->getID(),
+ HWAddrPtr(), 80));
+ lease->cltt_ = 1234;
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ // Check that the lease is really in the database
+ Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD,
+ prefix);
+ ASSERT_TRUE(l);
+
+ // Let's create a RELEASE
+ Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
+ req->setRemoteAddr(IOAddress("fe80::abcd"));
+ boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_PD, iaid, 1500, 3000);
+
+ OptionPtr released_addr_opt(new Option6IAPrefix(D6O_IAPREFIX, prefix, 80,
+ 300, 500));
+ ia->addOption(released_addr_opt);
+ req->addOption(ia);
+ req->addOption(clientid);
+
+ // Server-id is mandatory in RELEASE
+ req->addOption(srv.getServerID());
+
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRelease(req);
+
+ ASSERT_TRUE(reply);
// Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
+ EXPECT_EQ("lease6_release", callback_name_);
+
+ // Check that appropriate parameters are passed to the callouts
+ EXPECT_TRUE(callback_qry_pkt6_);
+ EXPECT_TRUE(callback_lease6_);
// Check if all expected parameters were really received
vector<string> expected_argument_names;
expected_argument_names.push_back("query6");
- expected_argument_names.push_back("deleted_leases6");
- expected_argument_names.push_back("leases6");
-
+ expected_argument_names.push_back("lease6");
+ sort(callback_argument_names_.begin(), callback_argument_names_.end());
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
- // Newly allocated lease should be returned.
- ASSERT_TRUE(callback_new_leases6_);
- ASSERT_EQ(1, callback_new_leases6_->size());
- Lease6Ptr lease = callback_new_leases6_->at(0);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
- EXPECT_EQ(64, lease->prefixlen_);
+ // Check that the lease is not gone in the database
+ // get lease by address
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD, prefix);
+ ASSERT_TRUE(l);
- // Deleted lease must not be present, because it is a new allocation.
- ASSERT_TRUE(callback_deleted_leases6_);
- EXPECT_TRUE(callback_deleted_leases6_->empty());
+ EXPECT_TRUE(l->expired());
+
+ // Get lease by subnetid/duid/iaid combination
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD, *duid_, iaid,
+ subnet_->getID());
+ ASSERT_TRUE(l);
+
+ EXPECT_TRUE(l->expired());
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
+ checkCalloutHandleReset(req);
+}
- resetCalloutBuffers();
+// This test verifies that skip flag returned by a callout installed on the
+// lease6_release hook point will keep the lease.
+TEST_F(HooksDhcpv6SrvTest, lease6ReleaseSkip) {
+ NakedDhcpv6Srv srv(0);
- // Rebind the lease and make sure that the callout has been executed.
- ASSERT_NO_THROW(client.doRebind());
+ // Install lease6_release_skip
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_release", lease6_release_skip));
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ const IOAddress addr("2001:db8:1:1::cafe:babe");
+ const uint32_t iaid = 234;
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
+ // Generate client-id also duid_
+ OptionPtr clientid = generateClientId();
- // Rebound lease should be returned.
- ASSERT_TRUE(callback_new_leases6_);
- ASSERT_EQ(1, callback_new_leases6_->size());
- lease = callback_new_leases6_->at(0);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
- EXPECT_EQ(64, lease->prefixlen_);
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
- // Deleted lease must not be present, because it is a new allocation.
- ASSERT_TRUE(callback_deleted_leases6_);
- EXPECT_TRUE(callback_deleted_leases6_->empty());
+ // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+ // value on purpose. They should be updated during RENEW.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
+ 501, 502, subnet_->getID(),
+ HWAddrPtr(), 0));
+ lease->cltt_ = 1234;
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
+ // Check that the lease is really in the database
+ Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr);
+ ASSERT_TRUE(l);
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
+ // Let's create a RELEASE
+ Pkt6Ptr rel = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
+ rel->setRemoteAddr(IOAddress("fe80::abcd"));
+ boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
- resetCalloutBuffers();
+ OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+ ia->addOption(released_addr_opt);
+ rel->addOption(ia);
+ rel->addOption(clientid);
- // Let's try to rebind again but force the client to rebind a different
- // prefix with a different IAID.
- client.requestPrefix(0x2233, 64, IOAddress("2001:db8:1:29::"));
+ // Server-id is mandatory in RELEASE
+ rel->addOption(srv.getServerID());
- ASSERT_NO_THROW(client.doRebind());
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRelease(rel);
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ ASSERT_TRUE(reply);
// Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
-
- // New lease should be returned.
- ASSERT_TRUE(callback_new_leases6_);
- ASSERT_EQ(2, callback_new_leases6_->size());
- lease = callback_new_leases6_->at(1);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1:29::", lease->addr_.toText());
- EXPECT_EQ(64, lease->prefixlen_);
+ EXPECT_EQ("lease6_release", callback_name_);
- // The old lease is kept.
- ASSERT_TRUE(callback_deleted_leases6_);
- ASSERT_TRUE(callback_deleted_leases6_->empty());
+ // Check that the lease is still there
+ // get lease by address
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr);
+ ASSERT_TRUE(l);
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
+ // Get lease by subnetid/duid/iaid combination
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
+ subnet_->getID());
+ ASSERT_TRUE(l);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
-
- resetCalloutBuffers();
+ checkCalloutHandleReset(rel);
+}
- // The rebound prefix is just a hint.
- client.requestPrefix(0x5577, 64, IOAddress("4000::1"));
+// This test verifies that drop flag returned by a callout installed on the
+// lease6_release hook point will keep the lease.
+TEST_F(HooksDhcpv6SrvTest, lease6ReleaseDrop) {
+ NakedDhcpv6Srv srv(0);
- ASSERT_NO_THROW(client.doRebind());
+ // Install lease6_release_drop
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_release", lease6_release_drop));
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ const IOAddress addr("2001:db8:1:1::cafe:babe");
+ const uint32_t iaid = 234;
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
+ // Generate client-id also duid_
+ OptionPtr clientid = generateClientId();
- ASSERT_TRUE(callback_new_leases6_);
- EXPECT_EQ(3, callback_new_leases6_->size());
- lease = callback_new_leases6_->at(2);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::", lease->addr_.toText());
- EXPECT_EQ(64, lease->prefixlen_);
- ASSERT_TRUE(callback_deleted_leases6_);
- EXPECT_TRUE(callback_deleted_leases6_->empty());
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
+ // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+ // value on purpose. They should be updated during RENEW.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
+ 501, 502, subnet_->getID(),
+ HWAddrPtr(), 0));
+ lease->cltt_ = 1234;
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
+ // Check that the lease is really in the database
+ Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr);
+ ASSERT_TRUE(l);
- resetCalloutBuffers();
+ // Let's create a RELEASE
+ Pkt6Ptr rel = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
+ rel->setRemoteAddr(IOAddress("fe80::abcd"));
+ boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
- // Rebind an address: this should lead to an error as no address pool
- // is configured.
- client.requestAddress(0x1122, IOAddress("2001:db8:1::28"));
+ OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+ ia->addOption(released_addr_opt);
+ rel->addOption(ia);
+ rel->addOption(clientid);
- ASSERT_NO_THROW(client.doRebind());
+ // Server-id is mandatory in RELEASE
+ rel->addOption(srv.getServerID());
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRelease(rel);
- // Check the error.
- EXPECT_EQ(STATUS_NoAddrsAvail, client.getStatusCode(0x1122));
+ ASSERT_TRUE(reply);
// Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
+ EXPECT_EQ("lease6_release", callback_name_);
- ASSERT_TRUE(callback_new_leases6_);
- EXPECT_EQ(3, callback_new_leases6_->size());
- ASSERT_TRUE(callback_deleted_leases6_);
- EXPECT_TRUE(callback_deleted_leases6_->empty());
+ // Check that the lease is still there
+ // get lease by address
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr);
+ ASSERT_TRUE(l);
+
+ // Get lease by subnetid/duid/iaid combination
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
+ subnet_->getID());
+ ASSERT_TRUE(l);
// Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
+ checkCalloutHandleReset(rel);
}
// This test checks that the basic decline hook (lease6_decline) is
// triggered properly.
-TEST_F(HooksDhcpv6SrvTest, basicLease6Decline) {
+TEST_F(HooksDhcpv6SrvTest, lease6DeclineSimple) {
IfaceMgrTestConfig test_config(true);
// Install lease6_decline callout
@@ -4799,139 +5120,7 @@ TEST_F(HooksDhcpv6SrvTest, lease6DeclineDrop) {
checkCalloutHandleReset(client.getContext().query_);
}
-// This test verifies that the leases6_committed callout is executed
-// when DECLINE is processed. The declined lease is expected to be passed
-// in leases6 argument to the callout.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedDecline) {
- IfaceMgrTestConfig test_config(true);
-
- string config = "{ \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- "},"
- "\"preferred-lifetime\": 3000,"
- "\"rebind-timer\": 2000, "
- "\"renew-timer\": 1000, "
- "\"subnet6\": [ { "
- " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
- " \"subnet\": \"2001:db8:1::/48\", "
- " \"interface\": \"eth1\" "
- " } ],"
- "\"valid-lifetime\": 4000 }";
-
- Dhcp6Client client;
- client.setInterface("eth1");
- client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
-
- ASSERT_NO_THROW(configure(config, *client.getServer()));
-
- ASSERT_NO_THROW(client.doSARR());
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
-
- ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases6_committed", leases6_committed_callout));
-
- ASSERT_NO_THROW(client.doDecline());
-
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
-
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query6");
- expected_argument_names.push_back("deleted_leases6");
- expected_argument_names.push_back("leases6");
-
- sort(expected_argument_names.begin(), expected_argument_names.end());
- EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
-
- // No deleted leases.
- ASSERT_TRUE(callback_deleted_leases6_);
- ASSERT_TRUE(callback_deleted_leases6_->empty());
-
- // Declined lease should be returned.
- ASSERT_TRUE(callback_new_leases6_);
- ASSERT_EQ(1, callback_new_leases6_->size());
- Lease6Ptr lease = callback_new_leases6_->at(0);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
-
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
-
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
-}
-
-// This test verifies that the leases6_committed callout is executed
-// when DECLINE is processed. Variant with 2 IA_NAs.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedDeclineTwoNAs) {
- IfaceMgrTestConfig test_config(true);
-
- string config = "{ \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- "},"
- "\"preferred-lifetime\": 3000,"
- "\"rebind-timer\": 2000, "
- "\"renew-timer\": 1000, "
- "\"subnet6\": [ { "
- " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
- " \"subnet\": \"2001:db8:1::/48\", "
- " \"interface\": \"eth1\" "
- " } ],"
- "\"valid-lifetime\": 4000 }";
-
- Dhcp6Client client;
- client.setInterface("eth1");
- client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
- client.requestAddress(0x2233, IOAddress("2001:db8:1::29"));
-
- ASSERT_NO_THROW(configure(config, *client.getServer()));
-
- ASSERT_NO_THROW(client.doSARR());
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
-
- ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases6_committed", leases6_committed_callout));
-
- ASSERT_NO_THROW(client.doDecline());
-
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases6_committed", callback_name_);
-
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query6");
- expected_argument_names.push_back("deleted_leases6");
- expected_argument_names.push_back("leases6");
-
- sort(expected_argument_names.begin(), expected_argument_names.end());
- EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
-
- // No deleted leases.
- ASSERT_TRUE(callback_deleted_leases6_);
- ASSERT_TRUE(callback_deleted_leases6_->empty());
-
- // Declined lease should be returned.
- ASSERT_TRUE(callback_new_leases6_);
- ASSERT_EQ(2, callback_new_leases6_->size());
- Lease6Ptr lease = callback_new_leases6_->at(0);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
- lease = callback_new_leases6_->at(1);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::29", lease->addr_.toText());
-
- // Pkt passed to a callout must be configured to copy retrieved options.
- EXPECT_TRUE(callback_qry_options_copy_);
-
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
-}
-
// Should test with one NA and two addresses but need an example first...
-
// Checks if callout installed on host6_identifier can generate an
// identifier and whether that identifier is actually used.
TEST_F(HooksDhcpv6SrvTest, host6Identifier) {
@@ -5015,9 +5204,9 @@ TEST_F(HooksDhcpv6SrvTest, host6Identifier) {
checkCalloutHandleReset(sol);
}
-// Checks if callout installed on host6_identifier can generate an identifier
+// Checks if callout installed on host6_identifier can generate an identifier of
// other type. This particular callout always returns hwaddr.
-TEST_F(HooksDhcpv6SrvTest, host6Identifier_hwaddr) {
+TEST_F(HooksDhcpv6SrvTest, host6IdentifierHWAddr) {
// Configure 2 subnets, both directly reachable over local interface
// (let's not complicate the matter with relays)
@@ -5053,7 +5242,7 @@ TEST_F(HooksDhcpv6SrvTest, host6Identifier_hwaddr) {
CfgMgr::instance().commit();
- // Install host6_identifier_foo_callout
+ // Install host6_identifier_hwaddr_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"host6_identifier", host6_identifier_hwaddr_callout));
@@ -5098,7 +5287,6 @@ TEST_F(HooksDhcpv6SrvTest, host6Identifier_hwaddr) {
checkCalloutHandleReset(sol);
}
-
// Verifies that libraries are unloaded by server destruction
// The callout libraries write their library index number to a marker
// file upon load and unload, making it simple to test whether or not
@@ -5270,7 +5458,7 @@ TEST_F(LoadUnloadDhcpv6SrvTest, Dhcpv6SrvConfigured) {
}
}
-// This test verifies that parked-packet-limit is enforced.
+// This test verifies that parked-packet-limit is properly enforced.
TEST_F(HooksDhcpv6SrvTest, leases6ParkedPacketLimit) {
IfaceMgrTestConfig test_config(true);
@@ -5400,5 +5588,4 @@ TEST_F(HooksDhcpv6SrvTest, leases6ParkedPacketLimit) {
EXPECT_EQ(1, getStatistic("pkt6-receive-drop"));
}
-
} // namespace