Parcourir la source

[4497] Enable copying retrieved options in callouts.

Marcin Siodelski il y a 8 ans
Parent
commit
9b2f0336a2

+ 22 - 0
src/bin/dhcp4/dhcp4_srv.cc

@@ -467,6 +467,9 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query) const {
         // We're reusing callout_handle from previous calls
         callout_handle->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
+
         // Set new arguments
         callout_handle->setArgument("query4", query);
         callout_handle->setArgument("subnet4", subnet);
@@ -735,6 +738,9 @@ Dhcpv4Srv::run_one() {
             // Delete previously set arguments
             callout_handle->deleteAllArguments();
 
+            // Enable copying options from the packet within hook library.
+            ScopedEnableOptionsCopy<Pkt4> resp4_options_copy(rsp);
+
             // Pass incoming packet as argument
             callout_handle->setArgument("response4", rsp);
 
@@ -804,6 +810,9 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
         // Delete previously set arguments
         callout_handle->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
+
         // Pass incoming packet as argument
         callout_handle->setArgument("query4", query);
 
@@ -894,6 +903,9 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
         // Delete previously set arguments
         callout_handle->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
+
         // Pass incoming packet as argument
         callout_handle->setArgument("query4", query);
 
@@ -983,6 +995,10 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
         // Clear skip flag if it was set in previous callouts
         callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
 
+        // Enable copying options from the query and response packet within
+        // hook library.
+        ScopedEnableOptionsCopy<Pkt4> query_resp_options_copy(query, rsp);
+
         // Set our response
         callout_handle->setArgument("response4", rsp);
 
@@ -2064,6 +2080,9 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
             // Delete all previous arguments
             callout_handle->deleteAllArguments();
 
+            // Enable copying options from the packet within hook library.
+            ScopedEnableOptionsCopy<Pkt4> query4_options_copy(release);
+
             // Pass the original packet
             callout_handle->setArgument("query4", release);
 
@@ -2207,6 +2226,9 @@ Dhcpv4Srv::declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline) {
         // Delete previously set arguments
         callout_handle->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt4> query4_options_copy(decline);
+
         // Pass incoming Decline and the lease to be declined.
         callout_handle->setArgument("lease4", lease);
         callout_handle->setArgument("query4", decline);

+ 80 - 0
src/bin/dhcp4/tests/hooks_unittest.cc

@@ -200,6 +200,10 @@ public:
         callout_handle.getArgument("query4", callback_qry_pkt4_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt4_) {
+            callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+        }
         return (0);
     }
 
@@ -245,6 +249,11 @@ public:
         callout_handle.getArgument("query4", callback_qry_pkt4_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt4_) {
+            callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -312,6 +321,15 @@ public:
         callout_handle.getArgument("query4", callback_qry_pkt4_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt4_) {
+            callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+        }
+
+        if (callback_resp_pkt4_) {
+            callback_resp_options_copy_ = callback_resp_pkt4_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -375,6 +393,11 @@ public:
         callout_handle.getArgument("response4", callback_resp_pkt4_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_resp_pkt4_) {
+            callback_resp_options_copy_ = callback_resp_pkt4_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -417,6 +440,11 @@ public:
         callout_handle.getArgument("subnet4collection", callback_subnet4collection_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt4_) {
+            callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -454,6 +482,11 @@ public:
         callout_handle.getArgument("lease4", callback_lease4_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt4_) {
+            callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -471,6 +504,11 @@ public:
         callout_handle.getArgument("clientid", callback_clientid_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt4_) {
+            callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -484,6 +522,10 @@ public:
         callout_handle.getArgument("query4", callback_qry_pkt4_);
         callout_handle.getArgument("lease4", callback_lease4_);
 
+        if (callback_qry_pkt4_) {
+            callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -509,6 +551,8 @@ public:
         callback_subnet4_.reset();
         callback_subnet4collection_ = NULL;
         callback_argument_names_.clear();
+        callback_qry_options_copy_ = false;
+        callback_resp_options_copy_ = false;
     }
 
     /// pointer to Dhcpv4Srv that is used in tests
@@ -542,6 +586,15 @@ public:
 
     /// A list of all received arguments
     static vector<string> callback_argument_names_;
+
+    /// Flag indicating if copying retrieved options was enabled for
+    /// a query during callout execution.
+    static bool callback_qry_options_copy_;
+
+    /// Flag indicating if copying retrieved options was enabled for
+    /// a response during callout execution.
+    static bool callback_resp_options_copy_;
+
 };
 
 // The following fields are used in testing pkt4_receive_callout.
@@ -555,6 +608,8 @@ ClientIdPtr HooksDhcpv4SrvTest::callback_clientid_;
 Lease4Ptr HooksDhcpv4SrvTest::callback_lease4_;
 const Subnet4Collection* HooksDhcpv4SrvTest::callback_subnet4collection_;
 vector<string> HooksDhcpv4SrvTest::callback_argument_names_;
+bool HooksDhcpv4SrvTest::callback_qry_options_copy_;
+bool HooksDhcpv4SrvTest::callback_resp_options_copy_;
 
 /// @brief Fixture class used to do basic library load/unload tests
 class LoadUnloadDhcpv4SrvTest : public ::testing::Test {
@@ -623,6 +678,9 @@ TEST_F(HooksDhcpv4SrvTest, Buffer4ReceiveSimple) {
     expected_argument_names.push_back(string("query4"));
 
     EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+    // Pkt passed to a callout must be configured to copy retrieved options.
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // Checks if callouts installed on buffer4_receive is able to change
@@ -728,6 +786,9 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSimple) {
     expected_argument_names.push_back(string("query4"));
 
     EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+    // Pkt passed to a callout must be configured to copy retrieved options.
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // Checks if callouts installed on pkt4_received is able to change
@@ -865,6 +926,10 @@ TEST_F(HooksDhcpv4SrvTest, pkt4SendSimple) {
     sort(callback_argument_names_.begin(), callback_argument_names_.end());
     sort(expected_argument_names.begin(), expected_argument_names.end());
     EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+    // Pkt passed to a callout must be configured to copy retrieved options.
+    EXPECT_TRUE(callback_qry_options_copy_);
+    EXPECT_TRUE(callback_resp_options_copy_);
 }
 
 // Checks if callouts installed on pkt4_send is able to change
@@ -1006,6 +1071,9 @@ TEST_F(HooksDhcpv4SrvTest, buffer4SendSimple) {
     vector<string> expected_argument_names;
     expected_argument_names.push_back(string("response4"));
     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_);
 }
 
 // Checks if callouts installed on buffer4_send are indeed called and that
@@ -1139,6 +1207,9 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
     // Compare that the available subnets are reported as expected
     EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet4collection_)[0].get());
     EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet4collection_)[1].get());
+
+    // Pkt passed to a callout must be configured to copy retrieved options.
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // This test checks if callout installed on subnet4_select hook point can pick
@@ -1300,6 +1371,9 @@ TEST_F(HooksDhcpv4SrvTest, lease4RenewSimple) {
     EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
 
     EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
+
+    // Pkt passed to a callout must be configured to copy retrieved options.
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // This test verifies that a callout installed on lease4_renew can trigger
@@ -1456,6 +1530,9 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimple) {
     sort(callback_argument_names_.begin(), callback_argument_names_.end());
     sort(expected_argument_names.begin(), expected_argument_names.end());
     EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+    // Pkt passed to a callout must be configured to copy retrieved options.
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // This test verifies that skip flag returned by a callout installed on the
@@ -1564,6 +1641,9 @@ TEST_F(HooksDhcpv4SrvTest, HooksDecline) {
     // the lease manager) all match.
     EXPECT_EQ(addr, from_mgr->addr_);
     EXPECT_EQ(addr, callback_lease4_->addr_);
+
+    // Pkt passed to a callout must be configured to copy retrieved options.
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // Checks that decline4 hook is able to drop the packet.

+ 18 - 0
src/bin/dhcp6/dhcp6_srv.cc

@@ -480,6 +480,9 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
     if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_receive_)) {
         CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
+
         // Delete previously set arguments
         callout_handle->deleteAllArguments();
 
@@ -575,6 +578,9 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
         // Delete previously set arguments
         callout_handle->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
+
         // Pass incoming packet as argument
         callout_handle->setArgument("query6", query);
 
@@ -717,6 +723,9 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
     if (HooksManager::calloutsPresent(Hooks.hook_index_pkt6_send_)) {
         CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
+        // Enable copying options from the packets within hook library.
+        ScopedEnableOptionsCopy<Pkt6> query_resp_options_copy(query, rsp);
+
         // Delete all previous arguments
         callout_handle->deleteAllArguments();
 
@@ -1014,6 +1023,9 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
         // We're reusing callout_handle from previous calls
         callout_handle->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt6> query6_options_copy(question);
+
         // Set new arguments
         callout_handle->setArgument("query6", question);
         callout_handle->setArgument("subnet6", subnet);
@@ -2023,6 +2035,9 @@ Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
     if (HooksManager::calloutsPresent(Hooks.hook_index_lease6_release_)) {
         CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
+
         // Delete all previous arguments
         callout_handle->deleteAllArguments();
 
@@ -2706,6 +2721,9 @@ Dhcpv6Srv::declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease,
         // Delete previously set arguments
         callout_handle->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt6> query6_options_copy(decline);
+
         // Pass incoming packet as argument
         callout_handle->setArgument("query6", decline);
         callout_handle->setArgument("lease6", lease);

+ 70 - 0
src/bin/dhcp6/tests/hooks_unittest.cc

@@ -147,6 +147,11 @@ public:
         callout_handle.getArgument("query6", callback_qry_pkt6_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -210,6 +215,11 @@ public:
         callout_handle.getArgument("query6", callback_qry_pkt6_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -284,6 +294,15 @@ public:
         callout_handle.getArgument("query6", callback_qry_pkt6_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
+        if (callback_resp_pkt6_) {
+            callback_resp_options_copy_ = callback_resp_pkt6_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -349,6 +368,11 @@ public:
         callout_handle.getArgument("subnet6collection", callback_subnet6collection_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -387,6 +411,11 @@ public:
         callout_handle.getArgument("ia_na", callback_ia_na_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -454,6 +483,11 @@ public:
         callout_handle.getArgument("ia_na", callback_ia_na_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -523,6 +557,11 @@ public:
         callout_handle.getArgument("lease6", callback_lease6_);
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -550,6 +589,10 @@ public:
         callout_handle.getArgument("query6", callback_qry_pkt6_);
         callout_handle.getArgument("lease6", callback_lease6_);
 
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -585,6 +628,8 @@ public:
         callback_ia_na_.reset();
         callback_subnet6collection_ = NULL;
         callback_argument_names_.clear();
+        callback_qry_options_copy_ = false;
+        callback_resp_options_copy_ = false;
     }
 
     /// Pointer to Dhcpv6Srv that is used in tests
@@ -615,6 +660,14 @@ public:
 
     /// A list of all received arguments
     static vector<string> callback_argument_names_;
+
+    /// Flag indicating if copying retrieved options was enabled for
+    /// a query during callout execution.
+    static bool callback_qry_options_copy_;
+
+    /// Flag indicating if copying retrieved options was enabled for
+    /// a response during callout execution.
+    static bool callback_resp_options_copy_;
 };
 
 // The following parameters are used by callouts to override
@@ -635,6 +688,8 @@ const Subnet6Collection* HooksDhcpv6SrvTest::callback_subnet6collection_;
 vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
 Lease6Ptr HooksDhcpv6SrvTest::callback_lease6_;
 boost::shared_ptr<Option6IA> HooksDhcpv6SrvTest::callback_ia_na_;
+bool HooksDhcpv6SrvTest::callback_qry_options_copy_;
+bool HooksDhcpv6SrvTest::callback_resp_options_copy_;
 
 /// @brief Fixture class used to do basic library load/unload tests
 class LoadUnloadDhcpv6SrvTest : public ::testing::Test {
@@ -702,6 +757,8 @@ TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Receive) {
     expected_argument_names.push_back(string("query6"));
 
     EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // Checks if callouts installed on buffer6_receive is able to change
@@ -823,6 +880,8 @@ TEST_F(HooksDhcpv6SrvTest, simplePkt6Receive) {
     expected_argument_names.push_back(string("query6"));
 
     EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // Checks if callouts installed on pkt6_received is able to change
@@ -947,6 +1006,9 @@ TEST_F(HooksDhcpv6SrvTest, simplePkt6Send) {
     expected_argument_names.push_back(string("query6"));
     expected_argument_names.push_back(string("response6"));
     EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+    EXPECT_TRUE(callback_qry_options_copy_);
+    EXPECT_TRUE(callback_resp_options_copy_);
 }
 
 // Checks if callouts installed on pkt6_send is able to change
@@ -1192,6 +1254,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet6SselectChange) {
     // in dynamic pool)
     EXPECT_TRUE((*subnets)[1]->inRange(addr_opt->getAddress()));
     EXPECT_TRUE((*subnets)[1]->inPool(Lease::TYPE_NA, addr_opt->getAddress()));
+
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // This test verifies that incoming (positive) RENEW can be handled properly,
@@ -1291,6 +1355,8 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Renew) {
     // Check that the returned lease6 in callout is the same as the one in the
     // database
     EXPECT_TRUE(*callback_lease6_ == *l);
+
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // This test verifies that incoming (positive) RENEW can be handled properly,
@@ -1537,6 +1603,8 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Release) {
     l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
                                               subnet_->getID());
     ASSERT_FALSE(l);
+
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // This test verifies that incoming (positive) RELEASE can be handled properly,
@@ -1907,6 +1975,8 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Decline) {
     // And that the parameters passed to callout are consistent with the database
     EXPECT_EQ(addr, from_mgr->addr_);
     EXPECT_EQ(addr, callback_lease6_->addr_);
+
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // Test that the lease6_decline hook point can handle SKIP status.

+ 56 - 0
src/lib/dhcp/pkt.h

@@ -14,11 +14,67 @@
 #include <dhcp/classify.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <utility>
 
 namespace isc {
 
 namespace dhcp {
 
+/// @brief RAII object enabling copying options retrieved from the
+/// packet.
+///
+/// This object enables copying retrieved options from a packet within
+/// a scope in which this object exists. When the object goes out of scope
+/// copying options is disabled. This is applicable in cases when the
+/// server is going to invoke a callout (hook library) where copying options
+/// must be enabled by default. When the callouts return copying options
+/// should be disabled. The use of RAII object eliminates the need for
+/// explicitly re-renabling options copying and is safer in case of
+/// exceptions thrown by callouts and a presence of multiple exit points.
+template<typename PktType>
+class ScopedEnableOptionsCopy {
+public:
+
+    /// @brief Pointer to an encapsulated packet.
+    typedef boost::shared_ptr<PktType> PktTypePtr;
+
+    /// @brief Constructor.
+    ///
+    /// Enables options copying on a packet(s).
+    ///
+    /// @param pkt1 Pointer to first packet.
+    /// @param pkt2 Optional pointer to the second packet.
+    ScopedEnableOptionsCopy(const PktTypePtr& pkt1,
+                            const PktTypePtr& pkt2 = PktTypePtr())
+        : pkts_(pkt1, pkt2) {
+        if (pkt1) {
+            pkt1->setCopyRetrievedOptions(true);
+        }
+        if (pkt2) {
+            pkt2->setCopyRetrievedOptions(true);
+        }
+    }
+
+    /// @brief Destructor.
+    ///
+    /// Disables options copying on a packets.
+    ~ScopedEnableOptionsCopy() {
+        if (pkts_.first) {
+            pkts_.first->setCopyRetrievedOptions(false);
+        }
+        if (pkts_.second) {
+            pkts_.second->setCopyRetrievedOptions(false);
+        }
+    }
+
+private:
+
+    /// @brief Holds a pointers to the packets.
+    std::pair<PktTypePtr, PktTypePtr> pkts_;
+};
+
 /// @brief Base class for classes representing DHCP messages.
 ///
 /// This is a base class that holds common information (e.g. source

+ 18 - 0
src/lib/dhcpsrv/alloc_engine.cc

@@ -1050,6 +1050,9 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx,
         // Delete all previous arguments
         ctx.callout_handle_->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt6> query6_options_copy(ctx.query_);
+
         // Pass necessary arguments
 
         // Pass the original packet
@@ -1120,6 +1123,9 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx,
         // Delete all previous arguments
         ctx.callout_handle_->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt6> query6_options_copy(ctx.query_);
+
         // Pass necessary arguments
 
         // Pass the original packet
@@ -1338,6 +1344,9 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) {
         // Delete all previous arguments
         callout_handle->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt6> query6_options_copy(ctx.query_);
+
         // Pass the original packet
         callout_handle->setArgument("query6", ctx.query_);
 
@@ -2524,6 +2533,9 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr) {
         // Delete all previous arguments
         ctx.callout_handle_->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt4> query4_options_copy(ctx.query_);
+
         // Pass necessary arguments
         // Pass the original client query
         ctx.callout_handle_->setArgument("query4", ctx.query_);
@@ -2629,6 +2641,9 @@ AllocEngine::renewLease4(const Lease4Ptr& lease,
         // Delete all previous arguments
         ctx.callout_handle_->deleteAllArguments();
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt4> query4_options_copy(ctx.query_);
+
         // Subnet from which we do the allocation. Convert the general subnet
         // pointer to a pointer to a Subnet4.  Note that because we are using
         // boost smart pointers here, we need to do the cast using the boost
@@ -2703,6 +2718,9 @@ AllocEngine::reuseExpiredLease4(Lease4Ptr& expired,
     if (ctx.callout_handle_ &&  HooksManager::getHooksManager()
         .calloutsPresent(hook_index_lease4_select_)) {
 
+        // Enable copying options from the packet within hook library.
+        ScopedEnableOptionsCopy<Pkt4> query4_options_copy(ctx.query_);
+
         // Delete all previous arguments
         ctx.callout_handle_->deleteAllArguments();
 

+ 22 - 0
src/lib/dhcpsrv/tests/alloc_engine_hooks_unittest.cc

@@ -45,6 +45,7 @@ public:
         callback_addr_original_ = IOAddress("::");
         callback_addr_updated_ = IOAddress("::");
         callback_qry_pkt6_.reset();
+        callback_qry_options_copy_ = false;
     }
 
     /// callback that stores received callout name and received values
@@ -61,6 +62,12 @@ public:
         callback_addr_original_ = callback_lease6_->addr_;
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ =
+                callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -102,6 +109,7 @@ public:
     static bool callback_fake_allocation_;
     static vector<string> callback_argument_names_;
     static Pkt6Ptr callback_qry_pkt6_;
+    static bool callback_qry_options_copy_;
 };
 
 // For some reason intialization within a class makes the linker confused.
@@ -122,6 +130,7 @@ Lease6Ptr HookAllocEngine6Test::callback_lease6_;
 bool HookAllocEngine6Test::callback_fake_allocation_;
 vector<string> HookAllocEngine6Test::callback_argument_names_;
 Pkt6Ptr HookAllocEngine6Test::callback_qry_pkt6_;
+bool HookAllocEngine6Test::callback_qry_options_copy_;
 
 // This test checks if the lease6_select callout is executed and expected
 // parameters as passed.
@@ -195,6 +204,8 @@ TEST_F(HookAllocEngine6Test, lease6_select) {
     sort(expected_argument_names.begin(), expected_argument_names.end());
 
     EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // This test checks if lease6_select callout is able to override the values
@@ -282,6 +293,7 @@ public:
         callback_addr_original_ = IOAddress("::");
         callback_addr_updated_ = IOAddress("::");
         callback_qry_pkt4_.reset();
+        callback_qry_options_copy_ = false;
     }
 
     /// callback that stores received callout name and received values
@@ -298,6 +310,12 @@ public:
         callback_addr_original_ = callback_lease4_->addr_;
 
         callback_argument_names_ = callout_handle.getArgumentNames();
+
+        if (callback_qry_pkt4_) {
+            callback_qry_options_copy_ =
+                callback_qry_pkt4_->isCopyRetrievedOptions();
+        }
+
         return (0);
     }
 
@@ -337,6 +355,7 @@ public:
     static bool callback_fake_allocation_;
     static vector<string> callback_argument_names_;
     static Pkt4Ptr callback_qry_pkt4_;
+    static bool callback_qry_options_copy_;
 };
 
 // For some reason intialization within a class makes the linker confused.
@@ -356,6 +375,7 @@ Lease4Ptr HookAllocEngine4Test::callback_lease4_;
 bool HookAllocEngine4Test::callback_fake_allocation_;
 vector<string> HookAllocEngine4Test::callback_argument_names_;
 Pkt4Ptr HookAllocEngine4Test::callback_qry_pkt4_;
+bool HookAllocEngine4Test::callback_qry_options_copy_;
 
 // This test checks if the lease4_select callout is executed and expected
 // parameters as passed.
@@ -428,6 +448,8 @@ TEST_F(HookAllocEngine4Test, lease4_select) {
     expected_argument_names.push_back("query4");
     expected_argument_names.push_back("subnet4");
     EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+    EXPECT_TRUE(callback_qry_options_copy_);
 }
 
 // This test checks if lease4_select callout is able to override the values