diff options
Diffstat (limited to 'src/bin/dhcp6/tests/hooks_unittest.cc')
-rw-r--r-- | src/bin/dhcp6/tests/hooks_unittest.cc | 2707 |
1 files changed, 1447 insertions, 1260 deletions
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 |