Browse Source

[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.
Marcin Siodelski 8 years ago
parent
commit
0a037d60ba
2 changed files with 143 additions and 0 deletions
  1. 6 0
      src/bin/dhcp6/dhcp6_srv.cc
  2. 137 0
      src/bin/dhcp6/tests/hooks_unittest.cc

+ 6 - 0
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<Pkt6> 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<Pkt6> query6_options_copy(query);
+
         // Pass the original packet
         callout_handle->setArgument("query6", query);
 

+ 137 - 0
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<string> 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<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("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("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.