]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5443] Updated DHCPv6 hook tests - finished?
authorFrancis Dupont <fdupont@isc.org>
Sat, 16 Dec 2017 11:16:03 +0000 (12:16 +0100)
committerFrancis Dupont <fdupont@isc.org>
Sat, 16 Dec 2017 11:16:03 +0000 (12:16 +0100)
src/bin/dhcp6/tests/hooks_unittest.cc

index 3f6ebefa3c1866d5e2d7cbe1df20fed5510f59e5..be61642d1f3fbd8eddef155e42098819668680d0 100644 (file)
@@ -218,6 +218,21 @@ public:
         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
+    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 pkt6_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
@@ -295,6 +310,17 @@ public:
         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
+    buffer6_receive_drop(CalloutHandle& callout_handle) {
+        callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
+
+        // Carry on as usual
+        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
@@ -369,6 +395,21 @@ public:
         return pkt6_send_callout(callout_handle);
     }
 
+    /// Test callback that sets drop flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    pkt6_send_drop(CalloutHandle& callout_handle) {
+
+        Pkt6Ptr pkt;
+        callout_handle.getArgument("response6", pkt);
+
+        callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
+
+        // carry on as usual
+        return pkt6_send_callout(callout_handle);
+    }
+
     /// @brief Test callback that stores response packet.
     /// @param callout_handle handle passed by the hooks framework.
     /// @return always 0
@@ -387,6 +428,30 @@ public:
         return (0);
     }
 
+    /// Test callback that sets skip flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    buffer6_send_skip(CalloutHandle& callout_handle) {
+
+        callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+
+        // carry on as usual
+        return buffer6_send_callout(callout_handle);
+    }
+
+    /// Test callback that sets drop flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    buffer6_send_drop(CalloutHandle& callout_handle) {
+
+        callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
+
+        // carry on as usual
+        return buffer6_send_callout(callout_handle);
+    }
+
     /// Test callback that stores received callout name and subnet6 values
     /// @param callout_handle handle passed by the hooks framework
     /// @return always 0
@@ -411,7 +476,7 @@ public:
     /// @param callout_handle handle passed by the hooks framework
     /// @return always 0
     static int
-    subnet6_select_different_subnet_callout(CalloutHandle& callout_handle) {
+    subnet6_select_different_subnet(CalloutHandle& callout_handle) {
 
         // Call the basic callout to record all passed values
         subnet6_select_callout(callout_handle);
@@ -430,6 +495,30 @@ public:
         return (0);
     }
 
+    /// Test callback that sets skip flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    subnet6_select_skip(CalloutHandle& callout_handle) {
+
+        callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+
+        // Carry on as usual
+        return subnet6_select_callout(callout_handle);
+    }
+
+    /// Test callback that sets drop flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    subnet6_select_drop(CalloutHandle& callout_handle) {
+
+        callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
+
+        // Carry on as usual
+        return subnet6_select_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
@@ -463,7 +552,7 @@ public:
     /// @param callout_handle handle passed by the hooks framework
     /// @return always 0
     static int
-    lease6_renew_update_callout(CalloutHandle& callout_handle) {
+    lease6_renew_update(CalloutHandle& callout_handle) {
         callback_name_ = string("lease6_renew");
 
         callout_handle.getArgument("query6", callback_qry_pkt6_);
@@ -527,7 +616,7 @@ public:
     /// @param callout_handle handle passed by the hooks framework
     /// @return always 0
     static int
-    lease6_rebind_update_callout(CalloutHandle& callout_handle) {
+    lease6_rebind_update(CalloutHandle& callout_handle) {
         callback_name_ = string("lease6_rebind");
 
         callout_handle.getArgument("query6", callback_qry_pkt6_);
@@ -559,7 +648,7 @@ public:
     /// @param callout_handle handle passed by the hooks framework
     /// @return always 0
     static int
-    lease6_rebind_skip_callout(CalloutHandle& callout_handle) {
+    lease6_rebind_skip(CalloutHandle& callout_handle) {
         callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
 
         return (lease6_rebind_callout(callout_handle));
@@ -600,7 +689,7 @@ public:
     /// @param callout_handle handle passed by the hooks framework
     /// @return always 0
     static int
-    lease6_release_skip_callout(CalloutHandle& callout_handle) {
+    lease6_release_skip(CalloutHandle& callout_handle) {
         callback_name_ = string("lease6_release");
 
         callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
@@ -608,6 +697,18 @@ public:
         return (0);
     }
 
+    /// Test callback that sets the drop flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    lease6_release_drop(CalloutHandle& callout_handle) {
+        callback_name_ = string("lease6_release");
+
+        callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
+
+        return (0);
+    }
+
     /// Lease6_decline test callback
     ///
     /// Stores all parameters in callback_* fields.
@@ -632,7 +733,7 @@ public:
     /// @param callout_handle handle passed by the hooks framework
     /// @return always 0
     static int
-    lease6_decline_skip_callout(CalloutHandle& callout_handle) {
+    lease6_decline_skip(CalloutHandle& callout_handle) {
         callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
 
         return (lease6_decline_callout(callout_handle));
@@ -643,7 +744,7 @@ public:
     /// @param callout_handle handle passed by the hooks framework
     /// @return always 0
     static int
-    lease6_decline_drop_callout(CalloutHandle& callout_handle) {
+    lease6_decline_drop(CalloutHandle& callout_handle) {
         callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
 
         return (lease6_decline_callout(callout_handle));
@@ -811,14 +912,14 @@ public:
     }
 };
 
-// Checks if callouts installed on pkt6_receive are indeed called and the
+// 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) {
 
-    // Install pkt6_receive_callout
+    // Install buffer6_receive_callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "buffer6_receive", buffer6_receive_callout));
 
@@ -854,7 +955,7 @@ TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Receive) {
 // the values and the parameters are indeed used by the server.
 TEST_F(HooksDhcpv6SrvTest, valueChangeBuffer6Receive) {
 
-    // Install pkt6_receive_callout
+    // Install buffer6_receive_change_clientid
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "buffer6_receive", buffer6_receive_change_clientid));
 
@@ -867,7 +968,7 @@ TEST_F(HooksDhcpv6SrvTest, valueChangeBuffer6Receive) {
     // 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.
+    // In particular, it should call registered buffer6_receive callback.
     srv_->run();
 
     // Check that the server did send a response
@@ -891,7 +992,7 @@ TEST_F(HooksDhcpv6SrvTest, valueChangeBuffer6Receive) {
 // client-id option is deleted, so the packet is expected to be dropped)
 TEST_F(HooksDhcpv6SrvTest, deleteClientIdBuffer6Receive) {
 
-    // Install pkt6_receive_callout
+    // Install buffer6_receive_delete_clientid
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "buffer6_receive", buffer6_receive_delete_clientid));
 
@@ -904,7 +1005,7 @@ TEST_F(HooksDhcpv6SrvTest, deleteClientIdBuffer6Receive) {
     // 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.
+    // In particular, it should call registered buffer6_receive callback.
     srv_->run();
 
     // Check that the server dropped the packet and did not send a response
@@ -915,7 +1016,7 @@ TEST_F(HooksDhcpv6SrvTest, deleteClientIdBuffer6Receive) {
 // will cause the server to not process the packet (drop), even though it is valid.
 TEST_F(HooksDhcpv6SrvTest, skipBuffer6Receive) {
 
-    // Install pkt6_receive_callout
+    // Install buffer6_receive_skip
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "buffer6_receive", buffer6_receive_skip));
 
@@ -928,7 +1029,31 @@ TEST_F(HooksDhcpv6SrvTest, skipBuffer6Receive) {
     // 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.
+    // In particular, it should call registered buffer6_receive callback.
+    srv_->run();
+
+    // Check that the server dropped the packet and did not produce any response
+    ASSERT_EQ(0, srv_->fake_sent_.size());
+}
+
+// Checks if callouts installed on buffer6_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, dropBuffer6Receive) {
+
+    // Install buffer6_receive_drop
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "buffer6_receive", buffer6_receive_drop));
+
+    // 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 buffer6_receive callback.
     srv_->run();
 
     // Check that the server dropped the packet and did not produce any response
@@ -978,7 +1103,7 @@ TEST_F(HooksDhcpv6SrvTest, simplePkt6Receive) {
 // the values and the parameters are indeed used by the server.
 TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Receive) {
 
-    // Install pkt6_receive_callout
+    // Install pkt6_receive_change_clientid
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "pkt6_receive", pkt6_receive_change_clientid));
 
@@ -1014,7 +1139,7 @@ TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Receive) {
 // client-id option is deleted, so the packet is expected to be dropped)
 TEST_F(HooksDhcpv6SrvTest, deleteClientIdPkt6Receive) {
 
-    // Install pkt6_receive_callout
+    // Install pkt6_receive_delete_clientid
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "pkt6_receive", pkt6_receive_delete_clientid));
 
@@ -1038,7 +1163,7 @@ TEST_F(HooksDhcpv6SrvTest, deleteClientIdPkt6Receive) {
 // will cause the server to not process the packet (drop), even though it is valid.
 TEST_F(HooksDhcpv6SrvTest, skipPkt6Receive) {
 
-    // Install pkt6_receive_callout
+    // Install pkt6_receive_skip
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "pkt6_receive", pkt6_receive_skip));
 
@@ -1058,12 +1183,36 @@ TEST_F(HooksDhcpv6SrvTest, skipPkt6Receive) {
     ASSERT_EQ(0, srv_->fake_sent_.size());
 }
 
+// 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) {
+
+    // Install pkt6_receive_drop
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "pkt6_receive", pkt6_receive_drop));
+
+    // 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 server dropped the packet and did not produce any response
+    ASSERT_EQ(0, srv_->fake_sent_.size());
+}
+
 
 // Checks if callouts installed on pkt6_send are indeed called and the
 // all necessary parameters are passed.
 TEST_F(HooksDhcpv6SrvTest, simplePkt6Send) {
 
-    // Install pkt6_receive_callout
+    // Install pkt6_send_callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "pkt6_send", pkt6_send_callout));
 
@@ -1076,7 +1225,7 @@ TEST_F(HooksDhcpv6SrvTest, simplePkt6Send) {
     // 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.
+    // In particular, it should call registered pkt6_send callback.
     srv_->run();
 
     // Check that the callback called is indeed the one we installed
@@ -1106,7 +1255,7 @@ TEST_F(HooksDhcpv6SrvTest, simplePkt6Send) {
 // the values and the packet sent contains those changes
 TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Send) {
 
-    // Install pkt6_receive_callout
+    // Install pkt6_send_change_serverid
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "pkt6_send", pkt6_send_change_serverid));
 
@@ -1119,7 +1268,7 @@ TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Send) {
     // 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.
+    // In particular, it should call registered pkt6_send callback.
     srv_->run();
 
     // Check that the server did send a response
@@ -1143,7 +1292,7 @@ TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Send) {
 // be sent
 TEST_F(HooksDhcpv6SrvTest, deleteServerIdPkt6Send) {
 
-    // Install pkt6_receive_callout
+    // Install pkt6_send_delete_serverid
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "pkt6_send", pkt6_send_delete_serverid));
 
@@ -1156,7 +1305,7 @@ TEST_F(HooksDhcpv6SrvTest, deleteServerIdPkt6Send) {
     // 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.
+    // In particular, it should call registered pkt6_send callback.
     srv_->run();
 
     // Check that the server indeed sent a malformed ADVERTISE
@@ -1171,10 +1320,10 @@ TEST_F(HooksDhcpv6SrvTest, deleteServerIdPkt6Send) {
 }
 
 // Checks if callouts installed on pkt6_skip is able to set skip flag that
-// will cause the server to not process the packet (drop), even though it is valid.
+// will cause the server to send an empty response.
 TEST_F(HooksDhcpv6SrvTest, skipPkt6Send) {
 
-    // Install pkt6_receive_callout
+    // Install pkt6_send_skip
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "pkt6_send", pkt6_send_skip));
 
@@ -1187,7 +1336,7 @@ TEST_F(HooksDhcpv6SrvTest, skipPkt6Send) {
     // 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.
+    // In particular, it should call registered pkt6_send callback.
     srv_->run();
 
     // Check that the server send the packet
@@ -1201,11 +1350,35 @@ TEST_F(HooksDhcpv6SrvTest, skipPkt6Send) {
     EXPECT_EQ(0, sent->getBuffer().getLength());
 }
 
+// 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) {
+
+    // Install pkt6_send_drop
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "pkt6_send", pkt6_send_drop));
+
+    // Let's create a simple REQUEST
+    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_send callback.
+    srv_->run();
+
+    // Check that the server does not send the packet
+    EXPECT_EQ(0, srv_->fake_sent_.size());
+}
+
 // 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
+    // Install buffer6_send_callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "buffer6_send", buffer6_send_callout));
 
@@ -1218,7 +1391,7 @@ TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Send) {
     // 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.
+    // In particular, it should call registered buffer6_send callback.
     srv_->run();
 
     // Check that the callback called is indeed the one we installed
@@ -1241,6 +1414,60 @@ TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Send) {
     EXPECT_TRUE(callback_resp_options_copy_);
 }
 
+// Checks if callouts installed on buffer6_send can set skip flag and that flag
+// causes the packet to not be sent
+TEST_F(HooksDhcpv6SrvTest, buffer6SendSkip) {
+
+    // Install buffer6_send_skip
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "buffer6_send", buffer6_send_skip));
+
+    // 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 buffer6_send callback.
+    srv_->run();
+
+    // 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());
+}
+
+// Checks if callouts installed on buffer6_send can set drop flag and that flag
+// causes the packet to not be sent
+TEST_F(HooksDhcpv6SrvTest, buffer6SendDrop) {
+
+    // Install buffer6_send_drop
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "buffer6_send", buffer6_send_drop));
+
+    // 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 buffer6_send callback.
+    srv_->run();
+
+    // 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());
+}
+
 // This test checks if subnet6_select callout is triggered and reports
 // valid parameters
 TEST_F(HooksDhcpv6SrvTest, subnet6Select) {
@@ -1275,7 +1502,7 @@ TEST_F(HooksDhcpv6SrvTest, subnet6Select) {
 
     CfgMgr::instance().commit();
 
-    // Install pkt6_receive_callout
+    // Install subnet6_select_callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "subnet6_select", subnet6_select_callout));
 
@@ -1352,9 +1579,9 @@ TEST_F(HooksDhcpv6SrvTest, subnet6SselectChange) {
 
     CfgMgr::instance().commit();
 
-    // Install pkt6_receive_callout
+    // Install subnet6_select_different_subnet
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "subnet6_select", subnet6_select_different_subnet_callout));
+                        "subnet6_select", subnet6_select_different_subnet));
 
     // Prepare solicit packet. Server should select first subnet for it
     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
@@ -1392,12 +1619,35 @@ TEST_F(HooksDhcpv6SrvTest, subnet6SselectChange) {
     EXPECT_TRUE((*subnets)[1]->inPool(Lease::TYPE_NA, addr_opt->getAddress()));
 }
 
+// Checks that subnet6_select is able to drop the packet.
+TEST_F(HooksDhcpv6SrvTest, subnet6SelectDrop) {
+
+    // Install subnet6_select_drop
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "subnet6_select", subnet6_select_drop));
+
+    // 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 subnet6_select callback.
+    srv_->run();
+
+    // Check that the server dropped the packet and did not produce any response
+    ASSERT_EQ(0, srv_->fake_sent_.size());
+}
+
 // 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 pkt6_receive_callout
+    // Install lease6_renew_callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "lease6_renew", lease6_renew_callout));
 
@@ -1499,9 +1749,9 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Renew) {
 TEST_F(HooksDhcpv6SrvTest, leaseUpdateLease6Renew) {
     NakedDhcpv6Srv srv(0);
 
-    // Install pkt6_receive_callout
+    // Install lease6_renew_update
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "lease6_renew", lease6_renew_update_callout));
+                        "lease6_renew", lease6_renew_update));
 
     const IOAddress addr("2001:db8:1:1::cafe:babe");
     const uint32_t iaid = 234;
@@ -1592,7 +1842,7 @@ TEST_F(HooksDhcpv6SrvTest, leaseUpdateLease6Renew) {
 TEST_F(HooksDhcpv6SrvTest, skipLease6Renew) {
     NakedDhcpv6Srv srv(0);
 
-    // Install pkt6_receive_callout
+    // Install lease6_renew_skip_callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "lease6_renew", lease6_renew_skip_callout));
 
@@ -1670,7 +1920,7 @@ TEST_F(HooksDhcpv6SrvTest, skipLease6Renew) {
 TEST_F(HooksDhcpv6SrvTest, basicLease6Release) {
     NakedDhcpv6Srv srv(0);
 
-    // Install pkt6_receive_callout
+    // Install lease6_release_callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "lease6_release", lease6_release_callout));
 
@@ -1748,7 +1998,7 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Release) {
 TEST_F(HooksDhcpv6SrvTest, basicLease6ReleasePD) {
     NakedDhcpv6Srv srv(0);
 
-    // Install pkt6_receive_callout
+    // Install lease6_release_callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "lease6_release", lease6_release_callout));
 
@@ -1822,21 +2072,78 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6ReleasePD) {
     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.
-//
-// 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
+// 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 pkt6_receive_callout
+    // Install lease6_release_skip
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "lease6_release", lease6_release_skip_callout));
+                        "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, 503, 504, 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);
+}
+
+// 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;
@@ -1898,7 +2205,7 @@ TEST_F(HooksDhcpv6SrvTest, skipLease6Release) {
 TEST_F(HooksDhcpv6SrvTest, basicLease6Rebind) {
     NakedDhcpv6Srv srv(0);
 
-    // Install pkt6_receive_callout
+    // Install lease6_rebind_callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
                         "lease6_rebind", lease6_rebind_callout));
 
@@ -1994,9 +2301,9 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Rebind) {
 TEST_F(HooksDhcpv6SrvTest, leaseUpdateLease6Rebind) {
     NakedDhcpv6Srv srv(0);
 
-    // Install pkt6_receive_callout
+    // Install lease6_rebind_update
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "lease6_rebind", lease6_rebind_update_callout));
+                        "lease6_rebind", lease6_rebind_update));
 
     const IOAddress addr("2001:db8:1:1::cafe:babe");
     const uint32_t iaid = 234;
@@ -2084,9 +2391,9 @@ TEST_F(HooksDhcpv6SrvTest, leaseUpdateLease6Rebind) {
 TEST_F(HooksDhcpv6SrvTest, skipLease6Rebind) {
     NakedDhcpv6Srv srv(0);
 
-    // Install pkt6_receive_callout
+    // Install lease6_rebind_skip
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "lease6_rebind", lease6_rebind_skip_callout));
+                        "lease6_rebind", lease6_rebind_skip));
 
     const IOAddress addr("2001:db8:1:1::cafe:babe");
     const uint32_t iaid = 234;
@@ -2205,9 +2512,9 @@ TEST_F(HooksDhcpv6SrvTest, lease6DeclineSkip) {
     // Libraries will be reloaded later
     HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
 
-    // Install lease6_decline callout. It will set the status to skip
+    // Install lease6_decline_skip callout. It will set the status to skip
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "lease6_decline", lease6_decline_skip_callout));
+                        "lease6_decline", lease6_decline_skip));
 
     // Get an address and decline it. DUIDs, IAID match and we send valid
     // address, so the decline procedure should be successful.
@@ -2252,9 +2559,9 @@ TEST_F(HooksDhcpv6SrvTest, lease6DeclineDrop) {
     // Libraries will be reloaded later
     HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
 
-    // Install lease6_decline callout. It will set the status to skip
+    // Install lease6_decline_drop callout. It will set the status to drop
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "lease6_decline", lease6_decline_drop_callout));
+                        "lease6_decline", lease6_decline_drop));
 
     // Get an address and decline it. DUIDs, IAID match and we send valid
     // address, so it would work, but the callout sets status to DROP, so