From: Marcin Siodelski Date: Fri, 8 Jul 2016 08:51:53 +0000 (+0200) Subject: [4497] Enable retrieved options copying for remaining DHCPv6 hooks. X-Git-Tag: trac4551_base~23^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a037d60baf42be7745f4a57a645563abd56a4c6;p=thirdparty%2Fkea.git [4497] Enable retrieved options copying for remaining DHCPv6 hooks. buffer6_send and lease6_release (PD case) hook points didn't set copying retrieved options flag for a packet passed to callouts. --- diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 8d522575dc..58893bb15a 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -438,6 +438,9 @@ void Dhcpv6Srv::run_one() { // Delete previously set arguments callout_handle->deleteAllArguments(); + // Enable copying options from the packet within hook library. + ScopedEnableOptionsCopy response6_options_copy(rsp); + // Pass incoming packet as argument callout_handle->setArgument("response6", rsp); @@ -2199,6 +2202,9 @@ Dhcpv6Srv::releaseIA_PD(const DuidPtr& duid, const Pkt6Ptr& query, // Delete all previous arguments callout_handle->deleteAllArguments(); + // Enable copying options from the packet within hook library. + ScopedEnableOptionsCopy query6_options_copy(query); + // Pass the original packet callout_handle->setArgument("query6", query); diff --git a/src/bin/dhcp6/tests/hooks_unittest.cc b/src/bin/dhcp6/tests/hooks_unittest.cc index 9fbdbe7878..c79fa836e2 100644 --- a/src/bin/dhcp6/tests/hooks_unittest.cc +++ b/src/bin/dhcp6/tests/hooks_unittest.cc @@ -356,6 +356,24 @@ public: return pkt6_send_callout(callout_handle); } + /// @brief Test callback that stores reponse 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_); + + if (callback_resp_pkt6_) { + callback_resp_options_copy_ = callback_resp_pkt6_->isCopyRetrievedOptions(); + } + + return (0); + } + /// Test callback that stores received callout name and subnet6 values /// @param callout_handle handle passed by the hooks framework /// @return always 0 @@ -1113,6 +1131,46 @@ TEST_F(HooksDhcpv6SrvTest, skipPkt6Send) { EXPECT_EQ(0, sent->getBuffer().getLength()); } +// Checks if callouts installed on buffer6_send are indeed called and the +// all necessary parameters are passed. +TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Send) { + + // Install pkt6_receive_callout + EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout( + "buffer6_send", buffer6_send_callout)); + + // Let's create a simple SOLICIT + Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit()); + + // Simulate that we have received that traffic + srv_->fakeReceive(sol); + + // Server will now process to run its normal loop, but instead of calling + // IfaceMgr::receive6(), it will read all packets from the list set by + // fakeReceive() + // In particular, it should call registered pkt6_receive callback. + srv_->run(); + + // Check that the callback called is indeed the one we installed + EXPECT_EQ("buffer6_send", callback_name_); + + // Check that there is one packet sent + ASSERT_EQ(1, srv_->fake_sent_.size()); + Pkt6Ptr adv = srv_->fake_sent_.front(); + + // Check that pkt6 argument passing was successful and returned proper + // values + EXPECT_TRUE(callback_resp_pkt6_.get() == adv.get()); + + // Check that all expected parameters are there + vector expected_argument_names; + expected_argument_names.push_back(string("response6")); + EXPECT_TRUE(expected_argument_names == callback_argument_names_); + + // Pkt passed to a callout must be configured to copy retrieved options. + EXPECT_TRUE(callback_resp_options_copy_); +} + // This test checks if subnet6_select callout is triggered and reports // valid parameters TEST_F(HooksDhcpv6SrvTest, subnet6Select) { @@ -1613,6 +1671,85 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Release) { EXPECT_TRUE(callback_qry_options_copy_); } +// 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 pkt6_receive_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, 503, 504, subnet_->getID(), + HWAddrPtr(), 80)); + 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_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 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("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 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_); +} + // 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.