]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5443] Checkpoint: updated DHCPv6 (todo hook tests)
authorFrancis Dupont <fdupont@isc.org>
Fri, 15 Dec 2017 23:45:06 +0000 (00:45 +0100)
committerFrancis Dupont <fdupont@isc.org>
Fri, 15 Dec 2017 23:45:06 +0000 (00:45 +0100)
src/bin/dhcp4/dhcp4_messages.mes
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp6/dhcp6_hooks.dox
src/bin/dhcp6/dhcp6_messages.mes
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/tests/classify_unittests.cc
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

index c6a7848400872e9caa12ea5795fd2c58bfe116d1..ce08958ecf555828d1c7669dd68dc75e3ef5d881 100644 (file)
@@ -288,7 +288,7 @@ client's request and acted on it (e.g. possibly allocated a lease).
 % DHCP4_HOOK_SUBNET4_SELECT_DROP %1: packet was dropped, because a callout set drop flag
 This debug message is printed when a callout installed on the
 subnet4_select hook point sets the drop flag. For this particular hook
-point, the setting of the flag instructs the server to drop the receive
+point, the setting of the flag instructs the server to drop the received
 packet. The argument specifies the client and transaction identification
 information.
 
index 84f1db40bf1b417c014d9aaba26a367168f3f757..03b3873d73af1a62481b030b3e25a212d95b42fa 100644 (file)
@@ -825,6 +825,7 @@ Dhcpv4Srv::run_one() {
         LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_BASIC,
                   DHCP4_PACKET_DROP_0008)
             .arg(query->getLabel());
+        return;
     } else {
         processPacket(query, rsp);
     }
index 6dc1fde806aabb538f078594d5e6ec35badcb961..abdd93bea4adf4a9c1e94033a2278f880f4a9dc5 100644 (file)
@@ -64,7 +64,9 @@ to the end of this list.
    in their raw form. Unless you need to access to the raw data, it is
    usually better to install your callout on the "pkt6_receive" hook point.
 
- - <b>Next step status</b>: If any callout sets the status to SKIP, the
+ - <b>Next step status</b>: If any callout sets the status to DROP, the server
+   will drop the packet and start processing the next one.
+   If any callout sets the status to SKIP, the
    server will assume that the callout parsed the buffer and added the
    necessary option objects to the @c options_ field; the server will not
    do any parsing. If the callout sets the skip flag but does not parse
@@ -89,7 +91,7 @@ to the end of this list.
    other fields in the Pkt6 object.  For this reason, modification of the
    @c data_ field would have no effect.)
 
- - <b>Next step status</b>: If any callout sets the status to SKIP, the server will
+ - <b>Next step status</b>: If any callout sets the status to SKIP (or DROP), the server will
    drop the packet and start processing the next one.  The reason for the drop
    will be logged if logging is set to the appropriate debug level.
 
@@ -107,7 +109,9 @@ to the end of this list.
    configured being provided as "subnet6collection". The list itself must
    not be modified.
 
- - <b>Next step status</b>: If any callout installed on "subnet6_select"
+ - <b>Next step status</b>: If any callout installed on "subnet6_select" sets
+   the status to DROP, the server will drop the packet and start processing
+   the next one. If any callout installed on "subnet6_select"
    sets the status to SKIP, the server will not select any subnet. Packet processing
    will continue, but will be severely limited.
 
@@ -258,7 +262,7 @@ to the end of this list.
    finish execution.
 
  - <b>Next step status</b>: If any callout installed on "lease6_release"
-   sets the status to SKIP, the server will not delete the lease, which will
+   sets the status to SKIP (or DROP), the server will not delete the lease, which will
    remain in the database until it expires. However, the server will send out
    the response back to the client as if it did.
 
@@ -283,8 +287,8 @@ to the end of this list.
    and option objects into the @c buffer_out_ field and will skip packing part.
    Note that if the callout sets skip flag, but did not prepare the
    output buffer, the server will send a zero sized message that will be
-   ignored by the client. If you want to drop the packet, please see
-   skip flag in the "buffer6_send" hook point.
+   ignored by the client. If any callout sets the status to DROP,
+   the server will drop the prepared response.
 
 @subsection dhcpv6HooksBuffer6Send buffer6_send
 
@@ -302,7 +306,7 @@ to the end of this list.
    to modify that data, it will probably be found easier to modify the
    option objects in a callout attached to the "pkt6_send" hook).
 
- - <b>Next step status</b>: If any callout sets the status to SKIP, the server
+ - <b>Next step status</b>: If any callout sets the status to SKIP (or DROP), the server
    will drop this response packet. However, the original request packet
    from a client has been processed, so server's state has most likely changed
    (e.g. lease was allocated). Setting this flag merely stops the change
index 0d6c9caebe892e93ddd4261d678ec869610e3672..21f4444ffeeb51904ee2b04f9ae34ccb42af65f9 100644 (file)
@@ -246,13 +246,21 @@ A "libreload" command was issued to reload the hooks libraries but for
 some reason the reload failed.  Other error messages issued from the
 hooks framework will indicate the nature of the problem.
 
-% DHCP6_HOOK_BUFFER_RCVD_SKIP received buffer from %1 to %2 over interface %3 was dropped because a callout set the skip flag
+% DHCP6_HOOK_BUFFER_RCVD_DROP received buffer from %1 to %2 over interface %3 was dropped because a callout set the drop flag
 This debug message is printed when a callout installed on buffer6_receive
-hook point set the skip flag. For this particular hook point, the
+hook point set the drop flag. For this particular hook point, the
 setting of the flag by a callout instructs the server to drop the packet.
 The arguments specify the source and destination address as well as
 the name of the interface over which the buffer has been received.
 
+% DHCP6_HOOK_BUFFER_RCVD_SKIP received buffer from %1 to %2 over interface %3 is not parsed because a callout set the skip flag
+This debug message is printed when a callout installed on
+buffer6_receive hook point set the skip flag. For this particular hook
+point, the setting of the flag by a callout instructs the server to
+not parse the buffer because it was already parsed by the hook. The
+arguments specify the source and destination address as well as the
+name of the interface over which the buffer has been received.
+
 % DHCP6_HOOK_BUFFER_SEND_SKIP %1: prepared DHCPv6 response was dropped because a callout set the skip flag
 This debug message is printed when a callout installed on buffer6_send
 hook point set the skip flag. For this particular hook point, the
@@ -300,15 +308,23 @@ This debug message is printed when a callout installed on the pkt6_receive
 hook point sets the skip flag. For this particular hook point, the
 setting of the flag instructs the server to drop the packet.
 
-% DHCP6_HOOK_PACKET_SEND_SKIP %1: prepared DHCPv6 response was not sent because a callout set the skip flag
+% DHCP6_HOOK_PACKET_SEND_DROP %1: prepared DHCPv6 response was not sent because a callout set the drop flag
 This debug message is printed when a callout installed on the pkt6_send
-hook point set the skip flag. For this particular hook point, the setting
+hook point set the drop flag. For this particular hook point, the setting
 of the flag by a callout instructs the server to drop the packet. This
 effectively means that the client will not get any response, even though
 the server processed client's request and acted on it (e.g. possibly
 allocated a lease). The argument specifies the client and transaction
 identification information.
 
+% DHCP6_HOOK_PACKET_SEND_SKIP %1: prepared DHCPv6 response is not built because a callout set the skip flag
+This debug message is printed when a callout installed on the
+pkt6_send hook point set the skip flag. For this particular hook
+point, the setting of the flag by a callout instructs the server to
+not build the wire data (pack) because it was already done by the
+book. The argument specifies the client and transaction identification
+information.
+
 % DHCP6_HOOK_SUBNET6_SELECT_SKIP %1: no subnet was selected because a callout set the skip flag
 This debug message is printed when a callout installed on the
 subnet6_select hook point set the skip flag. For this particular hook
@@ -318,6 +334,13 @@ will be only able to offer global options - no addresses or prefixes
 will be assigned. The argument holds the client and transaction
 identification information.
 
+% DHCP6_HOOK_SUBNET6_SELECT_DROP %1: packet was dropped because a callout set the drop flag
+This debug message is printed when a callout installed on the
+subnet6_select hook point set the drop flag. For this particular hook
+point, the setting of the flag instructs the server to drop the
+received packet. The argument holds the client and transaction
+identification information.
+
 % DHCP6_INIT_FAIL failed to initialize Kea server: %1
 The server has failed to establish communication with the rest of Kea,
 failed to read JSON configuration file or encountered any other critical
index 08c2dc13d23eb838ed9fc3b80cbb34bd08cbe5f5..6e3e084311174f21e81c2bf429924134df471aaa 100644 (file)
@@ -296,8 +296,10 @@ Dhcpv6Srv::testUnicast(const Pkt6Ptr& pkt) const {
 }
 
 void
-Dhcpv6Srv::initContext(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx) {
-    ctx.subnet_ = selectSubnet(pkt);
+Dhcpv6Srv::initContext(const Pkt6Ptr& pkt,
+                       AllocEngine::ClientContext6& ctx,
+                       bool& drop) {
+    ctx.subnet_ = selectSubnet(pkt, drop);
     ctx.duid_ = pkt->getClientId(),
     ctx.fwd_dns_update_ = false;
     ctx.rev_dns_update_ = false;
@@ -306,6 +308,11 @@ Dhcpv6Srv::initContext(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx) {
     ctx.callout_handle_ = getCalloutHandle(pkt);
     ctx.hwaddr_ = getMAC(pkt);
 
+    if (drop) {
+        // Caller will immediately drop the packet so simply return now.
+        return;
+    }
+
     // Collect host identifiers if host reservations enabled. The identifiers
     // are stored in order of preference. The server will use them in that
     // order to search for host reservations.
@@ -473,6 +480,7 @@ void Dhcpv6Srv::run_one() {
         LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_DETAIL_DATA,
                   DHCP6_PACKET_DROP_DHCP_DISABLED)
             .arg(query->getLabel());
+        return;
     } else {
         processPacket(query, rsp);
     }
@@ -505,14 +513,13 @@ void Dhcpv6Srv::run_one() {
             // Callouts decided to skip the next processing step. The next
             // processing step would to parse the packet, so skip at this
             // stage means drop.
-            if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
+            if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
+                (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
                 LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP)
                     .arg(rsp->getLabel());
                 return;
             }
 
-            /// @todo: Add support for DROP status
-
             callout_handle->getArgument("response6", rsp);
         }
 
@@ -562,7 +569,20 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
             skip_unpack = true;
         }
 
-        /// @todo: Add support for DROP status.
+        // Callouts decided to drop the received packet
+        // The response (rsp) is null so the caller (run_one) will
+        // immediately return too.
+        if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
+            LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_BUFFER_RCVD_DROP)
+                .arg(query->getRemoteAddr().toText())
+                .arg(query->getLocalAddr().toText())
+                .arg(query->getIface());
+
+            // Increase the statistic of dropped packets.
+            StatsMgr::instance().addValue("pkt6-receive-drop",
+                                          static_cast<int64_t>(1));
+            return;
+        }
 
         callout_handle->getArgument("query6", query);
     }
@@ -648,14 +668,16 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
         // Callouts decided to skip the next processing step. The next
         // processing step would to process the packet, so skip at this
         // stage means drop.
-        if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
+        if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
+            (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
             LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP)
                 .arg(query->getLabel());
+            // Increase the statistic of dropped packets.
+            StatsMgr::instance().addValue("pkt6-receive-drop",
+                                          static_cast<int64_t>(1));
             return;
         }
 
-        /// @todo: Add support for DROP status.
-
         callout_handle->getArgument("query6", query);
     }
 
@@ -807,7 +829,13 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
             skip_pack = true;
         }
 
-        /// @todo: Add support for DROP status
+        /// Callouts decided to drop the packet.
+        if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
+            LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_DROP)
+                .arg(rsp->getLabel());
+            rsp.reset();
+            return;
+        }
     }
 
     if (!skip_pack) {
@@ -1114,7 +1142,7 @@ Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
 }
 
 Subnet6Ptr
-Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
+Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question, bool& drop) {
     // Initialize subnet selector with the values used to select the subnet.
     SubnetSelector selector;
     selector.iface_name_ = question->getIface();
@@ -1174,7 +1202,14 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
             return (Subnet6Ptr());
         }
 
-        /// @todo: Add support for DROP status.
+        // Callouts decided to drop the packet. It is a superset of the
+        // skip case so no subnet will be selected.
+        if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
+            LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_SUBNET6_SELECT_DROP)
+                .arg(question->getLabel());
+            drop = true;
+            return (Subnet6Ptr());
+        }
 
         // Use whatever subnet was specified by the callout
         callout_handle->getArgument("subnet6", subnet);
@@ -2257,13 +2292,12 @@ Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
         // Callouts decided to skip the next processing step. The next
         // processing step would to send the packet, so skip at this
         // stage means "drop response".
-        if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
+        if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
+            (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
             skip = true;
             LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_LEASE6_RELEASE_NA_SKIP)
                 .arg(query->getLabel());
         }
-
-        /// @todo: Add support for DROP status
     }
 
     // Ok, we've passed all checks. Let's release this address.
@@ -2473,7 +2507,13 @@ Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
 
     // Let's create a simplified client context here.
     AllocEngine::ClientContext6 ctx;
-    initContext(solicit, ctx);
+    bool drop = false;
+    initContext(solicit, ctx, drop);
+
+    // Stop here if initContext decided to drop the packet.
+    if (drop) {
+        return (Pkt6Ptr());
+    }
 
     Pkt6Ptr response(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid()));
 
@@ -2522,7 +2562,13 @@ Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
 
     // Let's create a simplified client context here.
     AllocEngine::ClientContext6 ctx;
-    initContext(request, ctx);
+    bool drop = false;
+    initContext(request, ctx, drop);
+
+    // Stop here if initContext decided to drop the packet.
+    if (drop) {
+        return (Pkt6Ptr());
+    }
 
     Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, request->getTransid()));
 
@@ -2552,7 +2598,13 @@ Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
 
     // Let's create a simplified client context here.
     AllocEngine::ClientContext6 ctx;
-    initContext(renew, ctx);
+    bool drop = false;
+    initContext(renew, ctx, drop);
+
+    // Stop here if initContext decided to drop the packet.
+    if (drop) {
+        return (Pkt6Ptr());
+    }
 
     Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, renew->getTransid()));
 
@@ -2582,7 +2634,13 @@ Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
 
     // Let's create a simplified client context here.
     AllocEngine::ClientContext6 ctx;
-    initContext(rebind, ctx);
+    bool drop = false;
+    initContext(rebind, ctx, drop);
+
+    // Stop here if initContext decided to drop the packet.
+    if (drop) {
+        return (Pkt6Ptr());
+    }
 
     Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, rebind->getTransid()));
 
@@ -2612,7 +2670,14 @@ Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
 
     // Let's create a simplified client context here.
     AllocEngine::ClientContext6 ctx;
-    initContext(confirm, ctx);
+    bool drop = false;
+    initContext(confirm, ctx, drop);
+
+    // Stop here if initContext decided to drop the packet.
+    if (drop) {
+        return (Pkt6Ptr());
+    }
+
     setReservedClientClasses(confirm, ctx);
 
     // Get IA_NAs from the Confirm. If there are none, the message is
@@ -2705,7 +2770,14 @@ Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
 
     // Let's create a simplified client context here.
     AllocEngine::ClientContext6 ctx;
-    initContext(release, ctx);
+    bool drop = false;
+    initContext(release, ctx, drop);
+
+    // Stop here if initContext decided to drop the packet.
+    if (drop) {
+        return (Pkt6Ptr());
+    }
+
     setReservedClientClasses(release, ctx);
 
     Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, release->getTransid()));
@@ -2734,7 +2806,14 @@ Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
 
     // Let's create a simplified client context here.
     AllocEngine::ClientContext6 ctx;
-    initContext(decline, ctx);
+    bool drop = false;
+    initContext(decline, ctx, drop);
+
+    // Stop here if initContext decided to drop the packet.
+    if (drop) {
+        return (Pkt6Ptr());
+    }
+
     setReservedClientClasses(decline, ctx);
 
     // Copy client options (client-id, also relay information if present)
@@ -3015,7 +3094,14 @@ Dhcpv6Srv::processInfRequest(const Pkt6Ptr& inf_request) {
 
     // Let's create a simplified client context here.
     AllocEngine::ClientContext6 ctx;
-    initContext(inf_request, ctx);
+    bool drop = false;
+    initContext(inf_request, ctx, drop);
+
+    // Stop here if initContext decided to drop the packet.
+    if (drop) {
+        return (Pkt6Ptr());
+    }
+
     setReservedClientClasses(inf_request, ctx);
 
     // Create a Reply packet, with the same trans-id as the client's.
index 53d0d25a3c284a387b3eeb0e44949349065b47bd..d1a67ddef4e680ae4ae11646fdda5493f820dedd 100644 (file)
@@ -313,8 +313,9 @@ protected:
     /// @brief Selects a subnet for a given client's packet.
     ///
     /// @param question client's message
+    /// @param drop if it is true the packet will be dropped
     /// @return selected subnet (or NULL if no suitable subnet was found)
-    isc::dhcp::Subnet6Ptr selectSubnet(const Pkt6Ptr& question);
+    isc::dhcp::Subnet6Ptr selectSubnet(const Pkt6Ptr& question, bool& drop);
 
     /// @brief Processes IA_NA option (and assigns addresses if necessary).
     ///
@@ -688,7 +689,10 @@ protected:
     ///
     /// @param pkt pointer to a packet for which context will be created.
     /// @param [out] ctx reference to context object to be initialized.
-    void initContext(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx);
+    /// @param [out] drop if it is true the packet will be dropped.
+    void initContext(const Pkt6Ptr& pkt,
+                     AllocEngine::ClientContext6& ctx,
+                     bool& drop);
 
     /// @brief this is a prefix added to the content of vendor-class option
     ///
index 9b04d035c240e503e6bbfccc12829bd7f0032264..3ab0a9c2cfbcedd4350212d9ddffa65d1cc58796 100644 (file)
@@ -628,19 +628,23 @@ TEST_F(ClassifyTest, clientClassifySubnet) {
 
     // This discover does not belong to foo class, so it will not
     // be serviced
-    EXPECT_FALSE(srv_.selectSubnet(sol));
+    bool drop = false;
+    EXPECT_FALSE(srv_.selectSubnet(sol, drop));
+    EXPECT_FALSE(drop);
 
     // Let's add the packet to bar class and try again.
     sol->addClass("bar");
 
     // Still not supported, because it belongs to wrong class.
-    EXPECT_FALSE(srv_.selectSubnet(sol));
+    EXPECT_FALSE(srv_.selectSubnet(sol, drop));
+    EXPECT_FALSE(drop);
 
     // Let's add it to matching class.
     sol->addClass("foo");
 
     // This time it should work
-    EXPECT_TRUE(srv_.selectSubnet(sol));
+    EXPECT_TRUE(srv_.selectSubnet(sol, drop));
+    EXPECT_FALSE(drop);
 }
 
 // Tests whether a packet with custom vendor-class (not erouter or docsis)
@@ -733,12 +737,15 @@ TEST_F(ClassifyTest, relayOverrideAndClientClass) {
     // subnet[0], even though the relay-ip matches. It should be accepted in
     // subnet[1], because the subnet matches and there are no class
     // requirements.
-    EXPECT_TRUE(subnet2 == srv_.selectSubnet(sol));
+    bool drop = false;
+    EXPECT_TRUE(subnet2 == srv_.selectSubnet(sol, drop));
+    EXPECT_FALSE(drop);
 
     // Now let's add this packet to class foo and recheck. This time it should
     // be accepted in the first subnet, because both class and relay-ip match.
     sol->addClass("foo");
-    EXPECT_TRUE(subnet1 == srv_.selectSubnet(sol));
+    EXPECT_TRUE(subnet1 == srv_.selectSubnet(sol, drop));
+    EXPECT_FALSE(drop);
 }
 
 // This test checks that it is possible to specify static reservations for
index cb408c4b340cc2c403240a046b078aa109fbdffe..d6cac08161ae15aeee90b6200adba8b7c8b98766 100644 (file)
@@ -1233,7 +1233,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
 
     // The clause for assuming local subnet if there is only one subnet is was
     // removed.
-    EXPECT_FALSE(srv.selectSubnet(pkt));
+    bool drop = false;
+    EXPECT_FALSE(srv.selectSubnet(pkt, drop));
+    EXPECT_FALSE(drop);
 
     // CASE 2: We have only one subnet defined and we received relayed traffic.
     // We should NOT select it.
@@ -1243,8 +1245,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
     CfgMgr::instance().commit();
     pkt->setRemoteAddr(IOAddress("2001:db8:abcd::2345"));
-    Subnet6Ptr selected = srv.selectSubnet(pkt);
+    Subnet6Ptr selected = srv.selectSubnet(pkt, drop);
     EXPECT_FALSE(selected);
+    EXPECT_FALSE(drop);
 
     // CASE 3: We have three subnets defined and we received local traffic.
     // Nothing should be selected.
@@ -1254,8 +1257,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
     CfgMgr::instance().commit();
     pkt->setRemoteAddr(IOAddress("fe80::abcd"));
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_FALSE(selected);
+    EXPECT_FALSE(drop);
 
     // CASE 4: We have three subnets defined and we received relayed traffic
     // that came out of subnet 2. We should select subnet2 then
@@ -1265,8 +1269,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
     CfgMgr::instance().commit();
     pkt->setRemoteAddr(IOAddress("2001:db8:2::baca"));
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_EQ(selected, subnet2);
+    EXPECT_FALSE(drop);
 
     // CASE 5: We have three subnets defined and we received relayed traffic
     // that came out of undefined subnet. We should select nothing
@@ -1276,7 +1281,8 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
     CfgMgr::instance().commit();
     pkt->setRemoteAddr(IOAddress("2001:db8:4::baca"));
-    EXPECT_FALSE(srv.selectSubnet(pkt));
+    EXPECT_FALSE(srv.selectSubnet(pkt, drop));
+    EXPECT_FALSE(drop);
 }
 
 // This test verifies if selectSubnet() selects proper subnet for a given
@@ -1300,8 +1306,10 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
     Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     pkt->setIface("eth0");
 
-    Subnet6Ptr selected = srv.selectSubnet(pkt);
+    bool drop = false;
+    Subnet6Ptr selected = srv.selectSubnet(pkt, drop);
     EXPECT_EQ(selected, subnet1);
+    EXPECT_FALSE(drop);
 
     // CASE 2: We have only one subnet defined and it is available via eth0.
     // Packet came from eth1. We should not select it
@@ -1311,8 +1319,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
 
     pkt->setIface("eth1");
 
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_FALSE(selected);
+    EXPECT_FALSE(drop);
 
     // CASE 3: We have only 3 subnets defined, one over eth0, one remote and
     // one over wifi1.
@@ -1324,13 +1333,16 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
     CfgMgr::instance().commit();
 
     pkt->setIface("eth0");
-    EXPECT_EQ(subnet1, srv.selectSubnet(pkt));
+    EXPECT_EQ(subnet1, srv.selectSubnet(pkt, drop));
+    EXPECT_FALSE(drop);
 
     pkt->setIface("eth3"); // no such interface
-    EXPECT_EQ(Subnet6Ptr(), srv.selectSubnet(pkt)); // nothing selected
+    EXPECT_EQ(Subnet6Ptr(), srv.selectSubnet(pkt, drop)); // nothing selected
+    EXPECT_FALSE(drop);
 
     pkt->setIface("wifi1");
-    EXPECT_EQ(subnet3, srv.selectSubnet(pkt));
+    EXPECT_EQ(subnet3, srv.selectSubnet(pkt, drop));
+    EXPECT_FALSE(drop);
 }
 
 // This test verifies if selectSubnet() selects proper subnet for a given
@@ -1355,8 +1367,10 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
     Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     pkt->relay_info_.push_back(relay);
 
-    Subnet6Ptr selected = srv.selectSubnet(pkt);
+    bool drop = false;
+    Subnet6Ptr selected = srv.selectSubnet(pkt, drop);
     EXPECT_FALSE(selected);
+    EXPECT_FALSE(drop);
 
     // CASE 2: We have three subnets defined and we received relayed traffic
     // that came out of subnet 2. We should select subnet2 then
@@ -1365,22 +1379,25 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
     CfgMgr::instance().commit();
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_EQ(selected, subnet2);
+    EXPECT_FALSE(drop);
 
     // Source of the packet should have no meaning. Selection is based
     // on linkaddr field in the relay
     pkt->setRemoteAddr(IOAddress("2001:db8:1::baca"));
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_EQ(selected, subnet2);
+    EXPECT_FALSE(drop);
 
     // But not when this linkaddr field is not usable.
     Pkt6::RelayInfo relay2;
     relay2.peeraddr_ = IOAddress("fe80::1");
     pkt->relay_info_.clear();
     pkt->relay_info_.push_back(relay2);
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_EQ(selected, subnet1);
+    EXPECT_FALSE(drop);
 
     // CASE 3: We have three subnets defined and we received relayed traffic
     // that came out a layer 2 relay on subnet 2. We should select subnet2 then
@@ -1393,8 +1410,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
     pkt->relay_info_.push_back(relay);
     relay2.hop_count_ = 1;
     pkt->relay_info_.push_back(relay2);
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_EQ(selected, subnet2);
+    EXPECT_FALSE(drop);
 
     // The number of level 2 relay doesn't matter
     pkt->relay_info_.clear();
@@ -1415,8 +1433,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
     relay23.peeraddr_ = IOAddress("fe80::1");
     relay23.hop_count_ = 4;
     pkt->relay_info_.push_back(relay23);
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_EQ(selected, subnet2);
+    EXPECT_FALSE(drop);
 
     // Only the inner/last relay with a usable address matters
     pkt->relay_info_.clear();
@@ -1429,8 +1448,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
     relay3.peeraddr_ = IOAddress("fe80::1");
     relay3.hop_count_ = 4;
     pkt->relay_info_.push_back(relay3);
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_EQ(selected, subnet3);
+    EXPECT_FALSE(drop);
 
     // CASE 4: We have three subnets defined and we received relayed traffic
     // that came out of undefined subnet. We should select nothing
@@ -1443,9 +1463,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
     relay.hop_count_ = 0;
     relay.linkaddr_ = IOAddress("2001:db8:4::1234");
     pkt->relay_info_.push_back(relay);
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_FALSE(selected);
-
+    EXPECT_FALSE(drop);
 }
 
 // This test verifies if selectSubnet() selects proper subnet for a given
@@ -1475,16 +1495,19 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayInterfaceId) {
     pkt->relay_info_.push_back(relay);
 
     // There is only one subnet configured and we are outside of that subnet
-    Subnet6Ptr selected = srv.selectSubnet(pkt);
+    bool drop = false;
+    Subnet6Ptr selected = srv.selectSubnet(pkt, drop);
     EXPECT_FALSE(selected);
+    EXPECT_FALSE(drop);
 
     // CASE 2: We have only one subnet defined and it is for interface-id "relay2"
     // Packet came with interface-id "relay2". We should select it
     CfgMgr::instance().clear();
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2); // just a single subnet
     CfgMgr::instance().commit();
-    selected = srv.selectSubnet(pkt);
+    selected = srv.selectSubnet(pkt, drop);
     EXPECT_EQ(selected, subnet2);
+    EXPECT_FALSE(drop);
 
     // CASE 3: We have only 3 subnets defined: one remote for interface-id "relay1",
     // one remote for interface-id "relay2" and third local
@@ -1495,7 +1518,8 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayInterfaceId) {
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
     CfgMgr::instance().commit();
 
-    EXPECT_EQ(subnet2, srv.selectSubnet(pkt));
+    EXPECT_EQ(subnet2, srv.selectSubnet(pkt, drop));
+    EXPECT_FALSE(drop);
 }
 
 // Checks if server responses are sent to the proper port.
@@ -1974,24 +1998,30 @@ TEST_F(Dhcpv6SrvTest, relayOverride) {
 
     // This is just a sanity check, we're using regular method: the relay
     // belongs to the first (2001:db8:1::/64) subnet, so it's an easy decision.
-    EXPECT_TRUE(subnet1 == srv_.selectSubnet(sol));
+    bool drop = false;
+    EXPECT_TRUE(subnet1 == srv_.selectSubnet(sol, drop));
+    EXPECT_FALSE(drop);
 
     // Relay belongs to the second subnet, so it should be selected.
     sol->relay_info_.back().linkaddr_ = IOAddress("2001:db8:2::1");
-    EXPECT_TRUE(subnet2 == srv_.selectSubnet(sol));
+    EXPECT_TRUE(subnet2 == srv_.selectSubnet(sol, drop));
+    EXPECT_FALSE(drop);
 
     // Now let's check if the relay override for the first subnets works
     sol->relay_info_.back().linkaddr_ = IOAddress("2001:db8:3::1");
-    EXPECT_TRUE(subnet1 == srv_.selectSubnet(sol));
+    EXPECT_TRUE(subnet1 == srv_.selectSubnet(sol, drop));
+    EXPECT_FALSE(drop);
 
     // Now repeat that for relay matching the second subnet.
     sol->relay_info_.back().linkaddr_ = IOAddress("2001:db8:3::2");
-    EXPECT_TRUE(subnet2 == srv_.selectSubnet(sol));
+    EXPECT_TRUE(subnet2 == srv_.selectSubnet(sol, drop));
+    EXPECT_FALSE(drop);
 
     // Finally, let's check that completely mismatched relay will not get us
     // anything
     sol->relay_info_.back().linkaddr_ = IOAddress("2001:db8:1234::1");
-    EXPECT_FALSE(srv_.selectSubnet(sol));
+    EXPECT_FALSE(srv_.selectSubnet(sol, drop));
+    EXPECT_FALSE(drop);
 }
 
 /// @brief Creates RSOO option with suboptions