]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5458a] Checkpoint (dhcp6 to finish - lib to do)
authorFrancis Dupont <fdupont@isc.org>
Thu, 12 Apr 2018 14:07:47 +0000 (16:07 +0200)
committerFrancis Dupont <fdupont@isc.org>
Thu, 12 Apr 2018 14:07:47 +0000 (16:07 +0200)
17 files changed:
src/bin/dhcp6/ctrl_dhcp6_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/dhcp6to4_ipc.cc
src/bin/dhcp6/tests/Makefile.am
src/bin/dhcp6/tests/callout_library_1.cc
src/bin/dhcp6/tests/callout_library_2.cc
src/bin/dhcp6/tests/callout_library_3.cc [new file with mode: 0644]
src/bin/dhcp6/tests/callout_library_common.h
src/bin/dhcp6/tests/dhcp6_client.cc
src/bin/dhcp6/tests/dhcp6_client.h
src/bin/dhcp6/tests/dhcp6_test_utils.h
src/bin/dhcp6/tests/hooks_unittest.cc
src/bin/dhcp6/tests/marker_file.h.in
src/bin/dhcp6/tests/test_libraries.h.in

index f0d39bb6f90b0cfb4f2f62158b1e2dc1e00e1cd2..1e9362886874f7e45b8d8fb3a1adb320c228c782 100644 (file)
@@ -689,6 +689,7 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
         CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
 
         callout_handle->setArgument("io_context", srv->getIOService());
+        // callout_handle->setArgument("network_state", srv->getNetworkState());
         callout_handle->setArgument("json_config", config);
         callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
 
index 45afd6cb38b8ace4e9f879efe097b187dd8b083e..ec54ed20c16491b612a2cf84b0d5f5466c908548 100644 (file)
@@ -46,6 +46,26 @@ packet processing, but the exact order depends on the actual processing. Hook po
 that are not specific to packet processing (e.g. lease expiration) will be added
 to the end of this list.
 
+ @subsection dhcp6HooksDhcpv6SrvConfigured dhcp6_srv_configured
+ - @b Arguments:
+   - name: @b io_context, type: isc::asiolink::IOServicePtr, direction: <b>in</b>
+   - name: @b network_state, type: isc::dhcp::NetworkStatePtr, direction: <b>in</b>
+   - name: @b json_config, type: isc::data::ConstElementPtr, direction: <b>in</b>
+   - name: @b server_config, type: isc::dhcp::SrvConfigPtr, direction: <b>in</b>
+
+ - @b Description: this callout is executed when the server has completed
+   its (re)configuration. The server provides received and parsed configuration
+   structures to the hook library. It also provides a pointer to the IOService
+   object which is used by the server to run asynchronous operations. The hooks
+   libraries can use this IOService object to schedule asynchronous tasks which
+   are triggered by the DHCP server's main loop. The hook library should hold the
+   provided pointer until the library is unloaded. The NetworkState object
+   provides access to the DHCP service state of the server and allows for
+   enabling and disabling the DHCP service from the hooks libraries.
+
+ - <b>Next step status</b>: Status codes retured by the callouts installed on
+   this hook point are ignored.
+
  @subsection dhcpv6HooksBuffer6Receive buffer6_receive
 
  - @b Arguments:
@@ -266,6 +286,39 @@ to the end of this list.
    remain in the database until it expires. However, the server will send out
    the response back to the client as if it did.
 
+@subsection dhcpv6Leases6Committed leases6_committed
+
+ - @b Arguments:
+   - name: @b query6, type: isc::dhcp::Pkt6Ptr, direction: <b>in</b>
+   - name: @b leases6, type: isc::dhcp::Leases6CollectionPtr, direction: <b>in</b>
+   - name: @b deleted_leases6, type: isc::dhcp::Leases6CollectionPtr, direction: <b>in</b>
+
+ - @b Description: this callout is executed when the server has
+   applied all lease changes as a result of DHCP message
+   processing. This includes writing new lease into the database,
+   releasing an old lease for this client or declining a lease. This
+   callout is executed only for the DHCP client messages which may
+   cause lease changes, i.e. REQUEST, RENEW, REBIND, RELEASE and
+   DECLINE. This callout is not executed for SOLICIT, CONFIRM and
+   INFORMATION REQUEST.  If the callouts are executed as a result of
+   PREQUEST or RENEW message, it is possible that both leases
+   collections hold leases to be handled. This is the case when the
+   new lease allocation replaces an existing lease for the client. The
+   "deleted_leases6" object will hold a previous lease instance and
+   the "leases6" object will hold the new lease for this client. The
+   callouts should be prepared to handle such situation. When the
+   callout is executed as a result RELEASE or DECLINE, the callout
+   will typically receive only one lease (being released) in the
+   "deleted_leases6" object.  Both leases collections are always
+   provided to the callouts, even though they may sometimes be empty.
+
+ - <b>Next step status</b>: If any callout installed on the "leases6_committed"
+   sets the next step action to DROP the server will drop the processed query.
+   If it sets the next step action to PARK, the server will park the processed
+   packet (hold packet processing) until the hook libraries explicitly unpark
+   the packet after they are done performing asynchronous operations.
+
+
 @subsection dhcpv6HooksPkt6Send pkt6_send
 
  - @b Arguments:
index da4320145b24b46e8c775acc6c7cc869f3884217..28b3f13d6e9c13f35f0cf69f1f38102bd96c5525 100644 (file)
@@ -320,6 +320,14 @@ The server will skip the operation of moving the lease to the declined state and
 will continue processing the packet. In particular, it will send a REPLY message
 as if the decline actually took place.
 
+% DHCP6_HOOK_LEASES6_COMMITTED_DROP %1: packet is dropped, because a callout set the next step to DROP
+This debug message is printed when a callout installed on the leases6_committed
+hook point sets the next step to DROP.
+
+% DHCP6_HOOK_LEASES6_COMMITTED_PARK %1: packet is parked, because a callout set the next step to PARK
+This debug message is printed when a callout installed on the lease6_committed
+hook point sets the next step to PARK.
+
 % DHCP6_HOOK_LEASE6_RELEASE_NA_SKIP %1: DHCPv6 address lease was not released because a callout set the next step to SKIP
 This debug message is printed when a callout installed on the
 lease6_release hook point set the next step to SKIP. For this particular hook
index 987280acab940e3904425b2a15615f623320179c..66d906fcbc94a8c3e67ea1d2bf84f60e44391723 100644 (file)
@@ -29,7 +29,6 @@
 #include <dhcp6/dhcp6to4_ipc.h>
 #include <dhcp6/dhcp6_log.h>
 #include <dhcp6/dhcp6_srv.h>
-#include <dhcpsrv/callout_handle_store.h>
 #include <dhcpsrv/cfg_host_operations.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/lease_mgr.h>
@@ -94,34 +93,40 @@ namespace {
 
 /// Structure that holds registered hook indexes
 struct Dhcp6Hooks {
-    int hook_index_buffer6_receive_;///< index for "buffer6_receive" hook point
-    int hook_index_pkt6_receive_;   ///< index for "pkt6_receive" hook point
-    int hook_index_subnet6_select_; ///< index for "subnet6_select" hook point
-    int hook_index_lease6_release_; ///< index for "lease6_release" hook point
-    int hook_index_pkt6_send_;      ///< index for "pkt6_send" hook point
-    int hook_index_buffer6_send_;   ///< index for "buffer6_send" hook point
-    int hook_index_lease6_decline_; ///< index for "lease6_decline" hook point
-    int hook_index_host6_identifier_;///< index for "host6_identifier" hook point
+    int hook_index_buffer6_receive_;  ///< index for "buffer6_receive" hook point
+    int hook_index_pkt6_receive_;     ///< index for "pkt6_receive" hook point
+    int hook_index_subnet6_select_;   ///< index for "subnet6_select" hook point
+    int hook_index_leases6_committed_;///< index for "leases6_committed" hook point
+    int hook_index_lease6_release_;   ///< index for "lease6_release" hook point
+    int hook_index_pkt6_send_;        ///< index for "pkt6_send" hook point
+    int hook_index_buffer6_send_;     ///< index for "buffer6_send" hook point
+    int hook_index_lease6_decline_;   ///< index for "lease6_decline" hook point
+    int hook_index_host6_identifier_; ///< index for "host6_identifier" hook point
 
     /// Constructor that registers hook points for DHCPv6 engine
     Dhcp6Hooks() {
-        hook_index_buffer6_receive_ = HooksManager::registerHook("buffer6_receive");
-        hook_index_pkt6_receive_    = HooksManager::registerHook("pkt6_receive");
-        hook_index_subnet6_select_  = HooksManager::registerHook("subnet6_select");
-        hook_index_lease6_release_  = HooksManager::registerHook("lease6_release");
-        hook_index_pkt6_send_       = HooksManager::registerHook("pkt6_send");
-        hook_index_buffer6_send_    = HooksManager::registerHook("buffer6_send");
-        hook_index_lease6_decline_  = HooksManager::registerHook("lease6_decline");
-        hook_index_host6_identifier_= HooksManager::registerHook("host6_identifier");
+        hook_index_buffer6_receive_   = HooksManager::registerHook("buffer6_receive");
+        hook_index_pkt6_receive_      = HooksManager::registerHook("pkt6_receive");
+        hook_index_subnet6_select_    = HooksManager::registerHook("subnet6_select");
+        hook_index_leases6_committed_ = HooksManager::registerHook("leases6_committed");
+        hook_index_lease6_release_    = HooksManager::registerHook("lease6_release");
+        hook_index_pkt6_send_         = HooksManager::registerHook("pkt6_send");
+        hook_index_buffer6_send_      = HooksManager::registerHook("buffer6_send");
+        hook_index_lease6_decline_    = HooksManager::registerHook("lease6_decline");
+        hook_index_host6_identifier_  = HooksManager::registerHook("host6_identifier");
     }
 };
 
+} // end of anonymous namespace
+
 // Declare a Hooks object. As this is outside any function or method, it
 // will be instantiated (and the constructor run) when the module is loaded.
 // As a result, the hook indexes will be defined before any method in this
 // module is called.
 Dhcp6Hooks Hooks;
 
+namespace {
+
 /// @brief Creates instance of the Status Code option.
 ///
 /// This variant of the function is used when the Status Code option
@@ -488,55 +493,12 @@ void Dhcpv6Srv::run_one() {
         return;
     }
 
-    try {
-
-        // Now all fields and options are constructed into output wire buffer.
-        // Option objects modification does not make sense anymore. Hooks
-        // can only manipulate wire buffer at this stage.
-        // Let's execute all callouts registered for buffer6_send
-        if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_send_)) {
-            CalloutHandlePtr callout_handle = getCalloutHandle(query);
-
-            // Delete previously set arguments
-            callout_handle->deleteAllArguments();
-
-            // Enable copying options from the packet within hook library.
-            ScopedEnableOptionsCopy<Pkt6> response6_options_copy(rsp);
-
-            // Pass incoming packet as argument
-            callout_handle->setArgument("response6", rsp);
-
-            // Call callouts
-            HooksManager::callCallouts(Hooks.hook_index_buffer6_send_, *callout_handle);
-
-            // 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) ||
-                (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
-                LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP)
-                    .arg(rsp->getLabel());
-                return;
-            }
-
-            callout_handle->getArgument("response6", rsp);
-        }
-
-        LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_RESPONSE_DATA)
-            .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
-
-        sendPacket(rsp);
-
-        // Update statistics accordingly for sent packet.
-        processStatsSent(rsp);
-
-    } catch (const std::exception& e) {
-        LOG_ERROR(packet6_logger, DHCP6_PACKET_SEND_FAIL).arg(e.what());
-    }
+    CalloutHandlePtr callout_handle = getCalloutHandle(query);
+    processPacketBufferSend(callout_handle, rsp);
 }
 
 void
-Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
+Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp, bool allow_packet_park) {
     bool skip_unpack = false;
 
     // The packet has just been received so contains the uninterpreted wire
@@ -641,6 +603,9 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
         return;
     }
 
+    // Assign this packet to a class, if possible
+    classifyPacket(query);
+
     LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_PACKET_RECEIVED)
         .arg(query->getLabel())
         .arg(query->getName())
@@ -686,8 +651,7 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
         callout_handle->getArgument("query6", query);
     }
 
-    // Assign this packet to a class, if possible
-    classifyPacket(query);
+    AllocEngine::ClientContext6Ptr ctx;
 
     try {
         NameChangeRequestPtr ncr;
@@ -698,15 +662,15 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
             break;
 
         case DHCPV6_REQUEST:
-            rsp = processRequest(query);
+            rsp = processRequest(query, ctx);
             break;
 
         case DHCPV6_RENEW:
-            rsp = processRenew(query);
+            rsp = processRenew(query, ctx);
             break;
 
         case DHCPV6_REBIND:
-            rsp = processRebind(query);
+            rsp = processRebind(query, ctx);
             break;
 
         case DHCPV6_CONFIRM:
@@ -714,11 +678,11 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
             break;
 
         case DHCPV6_RELEASE:
-            rsp = processRelease(query);
+            rsp = processRelease(query, ctx);
             break;
 
         case DHCPV6_DECLINE:
-            rsp = processDecline(query);
+            rsp = processDecline(query, ctx);
             break;
 
         case DHCPV6_INFORMATION_REQUEST:
@@ -799,6 +763,88 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
     rsp->setIndex(query->getIndex());
     rsp->setIface(query->getIface());
 
+    bool packet_park = false;
+
+    if (ctx && HooksManager::calloutsPresent(Hooks.hook_index_leases6_committed_)) {
+        CalloutHandlePtr callout_handle = getCalloutHandle(query);
+
+        // Delete all previous arguments
+        callout_handle->deleteAllArguments();
+
+        // Clear skip flag if it was set in previous callouts
+        callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
+
+        ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
+
+        // Also pass the corresponding query packet as argument
+        callout_handle->setArgument("query6", query);
+
+        Lease6CollectionPtr new_leases(new Lease6Collection());
+        if (ctx->new_lease_) {
+            new_leases->push_back(ctx->new_lease_);
+        }
+        callout_handle->setArgument("leases6", new_leases);
+
+        Lease6CollectionPtr deleted_leases(new Lease6Collection());
+        if (ctx->old_lease_) {
+            if ((!ctx->new_lease_) || (ctx->new_lease_->addr_ != ctx->old_lease_->addr_)) {
+                deleted_leases->push_back(ctx->old_lease_);
+            }
+        }
+        callout_handle->setArgument("deleted_leases6", deleted_leases);
+
+        // Call all installed callouts
+        HooksManager::callCallouts(Hooks.hook_index_leases6_committed_,
+                                   *callout_handle);
+
+        if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
+            LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS,
+                      DHCP6_HOOK_LEASES6_COMMITTED_DROP)
+                .arg(query->getLabel());
+            rsp.reset();
+
+        } else if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_PARK)
+                   && allow_packet_park) {
+            packet_park = true;
+        }
+    }
+
+    if (!rsp) {
+        return;
+    }
+
+    // PARKING SPOT after leases6_committed hook point.
+    CalloutHandlePtr callout_handle = getCalloutHandle(query);
+    if (packet_park) {
+        LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS,
+                  DHCP6_HOOK_LEASES6_COMMITTED_PARK)
+            .arg(query->getLabel());
+
+        // Park the packet. The function we bind here will be executed when the hook
+        // library unparks the packet.
+        HooksManager::park("leases6_committed", query,
+        [this, callout_handle, query, rsp]() mutable {
+            processPacketPktSend(callout_handle, query, rsp);
+            processPacketBufferSend(callout_handle, rsp);
+        });
+
+        // If we have parked the packet, let's reset the pointer to the
+        // response to indicate to the caller that it should return, as
+        // the packet processing will continue via the callback.
+        rsp.reset();
+
+    } else {
+        processPacketPktSend(callout_handle, query, rsp);
+    }
+}
+
+void
+Dhcpv6Srv::processPacketPktSend(hooks::CalloutHandlePtr& callout_handle,
+                                Pkt6Ptr& query, Pkt6Ptr& rsp) {
+    if (!rsp) {
+        return;
+    }
+
     // Specifies if server should do the packing
     bool skip_pack = false;
 
@@ -807,7 +853,6 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
     // output wire data has not been prepared yet.
     // Execute all callouts registered for packet6_send
     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);
@@ -855,6 +900,60 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
     }
 }
 
+void
+Dhcpv6Srv::processPacketBufferSend(CalloutHandlePtr& callout_handle,
+                                   Pkt6Ptr& rsp) {
+    if (!rsp) {
+        return;
+    }
+
+    try {
+        // Now all fields and options are constructed into output wire buffer.
+        // Option objects modification does not make sense anymore. Hooks
+        // can only manipulate wire buffer at this stage.
+        // Let's execute all callouts registered for buffer6_send
+        if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_send_)) {
+
+            // Delete previously set arguments
+            callout_handle->deleteAllArguments();
+
+            // Enable copying options from the packet within hook library.
+            ScopedEnableOptionsCopy<Pkt6> response6_options_copy(rsp);
+
+            // Pass incoming packet as argument
+            callout_handle->setArgument("response6", rsp);
+
+            // Call callouts
+            HooksManager::callCallouts(Hooks.hook_index_buffer6_send_,
+                                       *callout_handle);
+
+            // 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) ||
+                (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
+                LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS,
+                          DHCP6_HOOK_BUFFER_SEND_SKIP)
+                    .arg(rsp->getLabel());
+                return;
+            }
+
+            callout_handle->getArgument("response6", rsp);
+        }
+
+        LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_RESPONSE_DATA)
+            .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
+
+        sendPacket(rsp);
+
+        // Update statistics accordingly for sent packet.
+        processStatsSent(rsp);
+
+    } catch (const std::exception& e) {
+        LOG_ERROR(packet6_logger, DHCP6_PACKET_SEND_FAIL).arg(e.what());
+    }
+}
+
 std::string
 Dhcpv6Srv::duidToString(const OptionPtr& opt) {
     stringstream tmp;
@@ -2516,7 +2615,6 @@ Dhcpv6Srv::releaseIA_PD(const DuidPtr& duid, const Pkt6Ptr& query,
 }
 
 
-
 Pkt6Ptr
 Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
 
@@ -2574,17 +2672,20 @@ Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
 }
 
 Pkt6Ptr
-Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
+Dhcpv6Srv::processRequest(const Pkt6Ptr& request,
+                          AllocEngine::ClientContext6Ptr& context) {
 
     sanityCheck(request, MANDATORY, MANDATORY);
 
     // Let's create a simplified client context here.
-    AllocEngine::ClientContext6 ctx;
+    context.reset(new AllocEngine::ClientContext6());
+    AllocEngine::ClientContext6& ctx = *context;
     bool drop = false;
     initContext(request, ctx, drop);
 
     // Stop here if initContext decided to drop the packet.
     if (drop) {
+        context.reset();
         return (Pkt6Ptr());
     }
 
@@ -2611,17 +2712,20 @@ Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
 }
 
 Pkt6Ptr
-Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
+Dhcpv6Srv::processRenew(const Pkt6Ptr& renew,
+                        AllocEngine::ClientContext6Ptr& context) {
 
     sanityCheck(renew, MANDATORY, MANDATORY);
 
     // Let's create a simplified client context here.
-    AllocEngine::ClientContext6 ctx;
+    context.reset(new AllocEngine::ClientContext6());
+    AllocEngine::ClientContext6& ctx = *context;
     bool drop = false;
     initContext(renew, ctx, drop);
 
     // Stop here if initContext decided to drop the packet.
     if (drop) {
+        context.reset();
         return (Pkt6Ptr());
     }
 
@@ -2648,17 +2752,20 @@ Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
 }
 
 Pkt6Ptr
-Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
+Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind,
+                         AllocEngine::ClientContext6Ptr& context) {
 
     sanityCheck(rebind, MANDATORY, FORBIDDEN);
 
     // Let's create a simplified client context here.
-    AllocEngine::ClientContext6 ctx;
+    context.reset(new AllocEngine::ClientContext6());
+    AllocEngine::ClientContext6& ctx = *context;
     bool drop = false;
     initContext(rebind, ctx, drop);
 
     // Stop here if initContext decided to drop the packet.
     if (drop) {
+        context.reset();
         return (Pkt6Ptr());
     }
 
@@ -2786,17 +2893,20 @@ Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
 }
 
 Pkt6Ptr
-Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
+Dhcpv6Srv::processRelease(const Pkt6Ptr& release,
+                          AllocEngine::ClientContext6Ptr& context) {
 
     sanityCheck(release, MANDATORY, MANDATORY);
 
     // Let's create a simplified client context here.
-    AllocEngine::ClientContext6 ctx;
+    context.reset(new AllocEngine::ClientContext6());
+    AllocEngine::ClientContext6& ctx = *context;
     bool drop = false;
     initContext(release, ctx, drop);
 
     // Stop here if initContext decided to drop the packet.
     if (drop) {
+        context.reset();
         return (Pkt6Ptr());
     }
 
@@ -2819,27 +2929,30 @@ Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
 }
 
 Pkt6Ptr
-Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
+Dhcpv6Srv::processDecline(const Pkt6Ptr& decline,
+                          AllocEngine::ClientContext6Ptr& context) {
 
     // Do sanity check.
     sanityCheck(decline, MANDATORY, MANDATORY);
 
-    // Create an empty Reply message.
-    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid()));
-
     // Let's create a simplified client context here.
-    AllocEngine::ClientContext6 ctx;
+    context.reset(new AllocEngine::ClientContext6());
+    AllocEngine::ClientContext6& ctx = *context;
     bool drop = false;
     initContext(decline, ctx, drop);
 
     // Stop here if initContext decided to drop the packet.
     if (drop) {
+        context.reset();
         return (Pkt6Ptr());
     }
 
     setReservedClientClasses(decline, ctx);
     requiredClassify(decline, ctx);
 
+    // Create an empty Reply message.
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid()));
+
     // Copy client options (client-id, also relay information if present)
     copyClientOptions(decline, reply);
 
@@ -2856,6 +2969,7 @@ Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
 
         // declineLeases returns false only if the hooks set the next step
         // status to DROP. We'll just doing as requested.
+        context.reset();
         return (Pkt6Ptr());
     }
 }
@@ -3006,7 +3120,7 @@ Dhcpv6Srv::declineIA(const Pkt6Ptr& decline, const DuidPtr& duid,
         }
 
         // Ok, all is good. Decline this lease.
-        if (!declineLease(decline, lease, ia_rsp)) {
+        if (!declineLease(decline, lease, ia_rsp, ctx)) {
             // declineLease returns false only when hook callouts set the next
             // step status to drop. We just propagate the bad news here.
             return (OptionPtr());
@@ -3033,7 +3147,8 @@ Dhcpv6Srv::setStatusCode(boost::shared_ptr<isc::dhcp::Option6IA>& container,
 
 bool
 Dhcpv6Srv::declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease,
-                        boost::shared_ptr<Option6IA> ia_rsp) {
+                        boost::shared_ptr<Option6IA> ia_rsp,
+                        AllocEngine::ClientContext6& ctx) {
     // We do not want to decrease the assigned-nas at this time. While
     // technically a declined address is no longer allocated, the primary usage
     // of the assigned-addresses statistic is to monitor pool utilization. Most
@@ -3102,6 +3217,8 @@ Dhcpv6Srv::declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease,
     lease->decline(CfgMgr::instance().getCurrentCfg()->getDeclinePeriod());
     LeaseMgrFactory::instance().updateLease6(lease);
 
+    ctx.new_lease_ = lease;
+
     LOG_INFO(lease6_logger, DHCP6_DECLINE_LEASE).arg(decline->getLabel())
         .arg(lease->addr_.toText()).arg(lease->valid_lft_);
 
index 898bd0c19503b992acbe4df08059e63924689305..55e07e21d1e011c774fdc99fa4fffb31daf30afb 100644 (file)
@@ -17,6 +17,7 @@
 #include <dhcp/option_definition.h>
 #include <dhcp/pkt6.h>
 #include <dhcpsrv/alloc_engine.h>
+#include <dhcpsrv/callout_handle_store.h>
 #include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/d2_client_mgr.h>
 #include <dhcpsrv/network_state.h>
@@ -24,6 +25,7 @@
 #include <hooks/callout_handle.h>
 #include <dhcpsrv/daemon.h>
 
+#include <functional>
 #include <iostream>
 #include <queue>
 
@@ -120,7 +122,9 @@ public:
     ///
     /// @param query A pointer to the packet to be processed.
     /// @param rsp A pointer to the response
-    void processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp);
+    /// @param allow_packet_park Indicates if parking a packet is allowed.
+    void processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp,
+                       bool allow_packet_park = true);
 
     /// @brief Instructs the server to shut down.
     void shutdown();
@@ -228,15 +232,21 @@ protected:
     /// leases.
     ///
     /// @param request a message received from client
+    /// @param [out] context pointer to the client context where allocated
+    /// and deleted leases are stored.
     ///
     /// @return REPLY message or NULL
-    Pkt6Ptr processRequest(const Pkt6Ptr& request);
+    Pkt6Ptr processRequest(const Pkt6Ptr& request,
+                           AllocEngine::ClientContext6Ptr& context);
 
     /// @brief Processes incoming Renew message.
     ///
     /// @param renew message received from the client
+    /// @param [out] context pointer to the client context where allocated
+    /// and deleted leases are stored.
     /// @return Reply message to be sent to the client.
-    Pkt6Ptr processRenew(const Pkt6Ptr& renew);
+    Pkt6Ptr processRenew(const Pkt6Ptr& renew,
+                         AllocEngine::ClientContext6Ptr& context);
 
     /// @brief Processes incoming Rebind message.
     ///
@@ -247,8 +257,11 @@ protected:
     /// now.
     ///
     /// @param rebind message received from the client.
+    /// @param [out] context pointer to the client context where allocated
+    /// and deleted leases are stored.
     /// @return Reply message to be sent to the client.
-    Pkt6Ptr processRebind(const Pkt6Ptr& rebind);
+    Pkt6Ptr processRebind(const Pkt6Ptr& rebind,
+                          AllocEngine::ClientContext6Ptr& context);
 
     /// @brief Processes incoming Confirm message and returns Reply.
     ///
@@ -278,8 +291,11 @@ protected:
     /// @brief Process incoming Release message.
     ///
     /// @param release message received from client
+    /// @param [out] context pointer to the client context where released
+    /// leases are stored.
     /// @return Reply message to be sent to the client.
-    Pkt6Ptr processRelease(const Pkt6Ptr& release);
+    Pkt6Ptr processRelease(const Pkt6Ptr& release,
+                           AllocEngine::ClientContext6Ptr& context);
 
     /// @brief Process incoming Decline message.
     ///
@@ -292,7 +308,10 @@ protected:
     ///                     options)
     ///
     /// @param decline message received from client
-    Pkt6Ptr processDecline(const Pkt6Ptr& decline);
+    /// @param [out] context pointer to the client context where declined
+    /// leases are stored.
+    Pkt6Ptr processDecline(const Pkt6Ptr& decline,
+                           AllocEngine::ClientContext6Ptr& context);
 
     /// @brief Processes incoming Information-request message.
     ///
@@ -881,6 +900,13 @@ public:
     /// @return the index of the buffer6_send hook
     static int getHookIndexBuffer6Send();
 
+    /// @brief Executes buffer6_send callout and sends the response.
+    ///
+    /// @param callout_handle pointer to the callout handle.
+    /// @param rsp pointer to a response.
+    void processPacketBufferSend(hooks::CalloutHandlePtr& callout_handle,
+                                 Pkt6Ptr& rsp);
+
 protected:
 
     /// Server DUID (to be sent in server-identifier option)
@@ -890,6 +916,14 @@ protected:
     /// initiate server shutdown procedure.
     volatile bool shutdown_;
 
+    /// @brief Executes pkt6_send callout.
+    ///
+    /// @param callout_handle pointer to the callout handle.
+    /// @param query Pointer to a query.
+    /// @param rsp Pointer to a response.
+    void processPacketPktSend(hooks::CalloutHandlePtr& callout_handle,
+                              Pkt6Ptr& query, Pkt6Ptr& rsp);
+
     /// @brief Allocation Engine.
     /// Pointer to the allocation engine that we are currently using
     /// It must be a pointer, because we will support changing engines
index 454cbd19c628f1f8ffd25d44e616cc8e7ce4fca9..8704288ad7709ee7b2742b1150ab2cdc7a51610d 100644 (file)
@@ -100,52 +100,8 @@ void Dhcp6to4Ipc::handler() {
 
     // Can't call the pkt6_send callout because we don't have the query
 
-    // Copied from Dhcpv6Srv::run_one() sending part
-
-    try {
-        // Let's execute all callouts registered for buffer6_send
-        if (HooksManager::calloutsPresent(Dhcpv6Srv::getHookIndexBuffer6Send())) {
-            CalloutHandlePtr callout_handle = getCalloutHandle(pkt);
-
-            // Delete previously set arguments
-            callout_handle->deleteAllArguments();
-
-            // Enable copying options from the packet within hook library.
-            ScopedEnableOptionsCopy<Pkt6> response6_options_copy(pkt);
-
-            // Pass incoming packet as argument
-            callout_handle->setArgument("response6", pkt);
-
-            // Call callouts
-            HooksManager::callCallouts(Dhcpv6Srv::getHookIndexBuffer6Send(),
-                                       *callout_handle);
-
-            // 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) ||
-                (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
-                LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP)
-                    .arg(pkt->getLabel());
-                return;
-            }
-
-            callout_handle->getArgument("response6", pkt);
-        }
-
-        LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_RESPONSE_DATA)
-            .arg(static_cast<int>(pkt->getType())).arg(pkt->toText());
-
-
-        // Forward packet to the client.
-        IfaceMgr::instance().send(pkt);
-
-        // Update statistics accordingly for sent packet.
-        Dhcpv6Srv::processStatsSent(pkt);
-
-    } catch (const std::exception& e) {
-        LOG_ERROR(packet6_logger, DHCP6_DHCP4O6_SEND_FAIL).arg(e.what());
-    }
+    ControlledDhcpv4Srv::getInstance()->
+        processPacketBufferSend(getCalloutHandle(pkt), pkt);
 }
 
 };  // namespace dhcp
index 1171de0f4928b901c0cd1cc9c9d198c8574afb33..70dfc4176b4df89c5ca5b0f1377cd23ce276c2d1 100644 (file)
@@ -57,7 +57,7 @@ if HAVE_GTEST
 # to unexpected errors. For this reason, the --enable-static-link option is
 # ignored for unit tests built here.
 
-noinst_LTLIBRARIES = libco1.la libco2.la
+noinst_LTLIBRARIES = libco1.la libco2.la libco3.la
 
 # -rpath /nowhere is a hack to trigger libtool to not create a
 # convenience archive, resulting in shared modules
@@ -72,6 +72,11 @@ libco2_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco2_la_CPPFLAGS = $(AM_CPPFLAGS)
 libco2_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
 
+libco3_la_SOURCES  = callout_library_3.cc callout_library_common.h
+libco3_la_CXXFLAGS = $(AM_CXXFLAGS)
+libco3_la_CPPFLAGS = $(AM_CPPFLAGS)
+libco3_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
 TESTS += dhcp6_unittests
 dhcp6_unittests_SOURCES  = dhcp6_unittests.cc
 dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
index 866652c6f6b2cdd8c7a91e9f80d0fa492b2ec02d..ffe05eba3f404064c030dfdbfcf74eeab19f0ddc 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -13,4 +13,4 @@
 static const int LIBRARY_NUMBER = 1;
 #include <config.h>
 
-#include "callout_library_common.h"
+#include <dhcp6/tests/callout_library_common.h>
index ae417a29697419429eb60c7790db85628be5277b..5dc72c52d19eb2ad7bb477427b81fe4574b45bb6 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -13,4 +13,4 @@
 static const int LIBRARY_NUMBER = 2;
 #include <config.h>
 
-#include "callout_library_common.h"
+#include <dhcp6/tests/callout_library_common.h>
diff --git a/src/bin/dhcp6/tests/callout_library_3.cc b/src/bin/dhcp6/tests/callout_library_3.cc
new file mode 100644 (file)
index 0000000..3305ac1
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+/// @file
+/// @brief Callout library for tesing execution of the dhcp6_srv_configured
+/// hook point.
+///
+static const int LIBRARY_NUMBER = 3;
+#include <dhcp6/tests/callout_library_common.h>
+#include <string>
+#include <vector>
+
+using namespace isc::hooks;
+
+extern "C" {
+
+/// @brief Callout which appends library number and provided arguments to
+/// the marker file for dhcp6_srv_configured callout.
+///
+/// @param handle callout handle passed to the callout.
+///
+/// @return 0 on success, 1 otherwise.
+int
+dhcp6_srv_configured(CalloutHandle& handle) {
+    // Append library number.
+    if (appendDigit(SRV_CONFIG_MARKER_FILE)) {
+        return (1);
+    }
+
+    // Append argument names.
+    std::vector<std::string> args = handle.getArgumentNames();
+    for (auto arg = args.begin(); arg != args.end(); ++arg) {
+        if (appendArgument(SRV_CONFIG_MARKER_FILE, arg->c_str()) != 0) {
+            return (1);
+        }
+    }
+
+    return (0);
+}
+
+}
index c3e3436591619eac980a0b7da7cf0b783472c8d6..36f459ab2e88ab00cf442d4add38f6e5bac379d1 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 /// can determine whether the load/unload functions have been run and, if so,
 /// in what order.
 ///
+/// The additional marker file is created for the dhcp6_srv_configured hook
+/// point. It records the library number and the names of the parameters
+/// provided to the callout.
+///
 /// This file is the common library file for the tests.  It will not compile
 /// by itself - it is included into each callout library which specifies the
 /// missing constant LIBRARY_NUMBER before the inclusion.
@@ -53,6 +57,26 @@ appendDigit(const char* name) {
     return (0);
 }
 
+/// @brief Append argument name passed to the callout to a marker file.
+///
+/// @param file_name Name of the file to open.
+/// @param parameter Parameter name.
+///
+/// @return 0 on success, non-zero on error.
+int appendArgument(const char* file_name, const char* argument) {
+    // Open the file and check if successful.
+    std::fstream file(file_name, std::fstream::out | std::fstream::app);
+    if (!file.good()) {
+        return (1);
+    }
+
+    // Add the library number to it and close.
+    file << argument;
+    file.close();
+
+    return (0);
+}
+
 // Framework functions
 int
 version() {
index 8ab931cd6cf681ac0ec175bd0dbae884b5b350b8..32ed802f79e973bcb7dc8cd21f4345765e8f6077 100644 (file)
@@ -900,6 +900,16 @@ Dhcp6Client::receiveOneMsg() {
     return (msg);
 }
 
+void
+Dhcp6Client::receiveResponse() {
+    context_.response_ = receiveOneMsg();
+    // If the server has responded, store the configuration received.
+    if (context_.response_) {
+        config_.clear();
+        applyRcvdConfiguration(context_.response_);
+    }
+}
+
 void
 Dhcp6Client::sendMsg(const Pkt6Ptr& msg) {
     srv_->shutdown_ = false;
@@ -944,7 +954,14 @@ Dhcp6Client::sendMsg(const Pkt6Ptr& msg) {
     }
 
     srv_->fakeReceive(msg_copy);
-    srv_->run();
+
+    try {
+        // Invoke run_one instead of run, because we want to avoid triggering
+        // IO service.
+        srv_->run_one();
+    } catch (...) {
+        // Suppress errors, as the DHCPv6 server does.
+    }
 }
 
 void
index 80ff2c37c14248e8c00a1ee89b55fa9b2de366b7..4a2b86df8b8d6f2a1e97c57516ed8c8e54c8a569 100644 (file)
@@ -767,6 +767,15 @@ public:
     /// is incomplete. Please extend it when needed.
     void printConfiguration() const;
 
+    /// @brief Receives a response from the server.
+    ///
+    /// This method is useful to receive response from the server after
+    /// parking a packet. In this case, the packet is not received as a
+    /// result of initial exchange, e.g. @c doRequest. The test can call
+    /// this method to complete the transaction when it expects that the
+    /// packet has been unparked.
+    void receiveResponse();
+
 private:
 
     /// @brief Applies the new leases for the client.
index 7b99db54b9c8e97e694643b69e49756de8377e95..52fe5a02a174bf2bbc9c1c4de84a8859b9edf310 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -183,6 +183,51 @@ public:
         isc::dhcp::LeaseMgrFactory::destroy();
     }
 
+    /// @brief Processes incoming Request message.
+    ///
+    /// @param request a message received from client
+    /// @return REPLY message or NULL
+    Pkt6Ptr processRequest(const Pkt6Ptr& request) {
+        AllocEngine::ClientContext6Ptr context(new AllocEngine::ClientContext6());
+        return (processRequest(request, context));
+    }
+
+    /// @brief Processes incoming Renew message.
+    ///
+    /// @param renew a message received from client
+    /// @return REPLY message or NULL
+    Pkt6Ptr processRenew(const Pkt6Ptr& renew) {
+        AllocEngine::ClientContext6Ptr context(new AllocEngine::ClientContext6());
+        return (processRenew(renew, context));
+    }
+
+    /// @brief Processes incoming Rebind message.
+    ///
+    /// @param rebind a message received from client
+    /// @return REPLY message or NULL
+    Pkt6Ptr processRebind(const Pkt6Ptr& rebind) {
+        AllocEngine::ClientContext6Ptr context(new AllocEngine::ClientContext6());
+        return (processRebind(rebind, context));
+    }
+
+    /// @brief Processes incoming Release message.
+    ///
+    /// @param release a message received from client
+    /// @return REPLY message or NULL
+    Pkt6Ptr processRelease(const Pkt6Ptr& release) {
+        AllocEngine::ClientContext6Ptr context(new AllocEngine::ClientContext6());
+        return (processRelease(release, context));
+    }
+
+    /// @brief Processes incoming Decline message.
+    ///
+    /// @param decline a message received from client
+    /// @return REPLY message or NULL
+    Pkt6Ptr processDecline(const Pkt6Ptr& decline) {
+        AllocEngine::ClientContext6Ptr context(new AllocEngine::ClientContext6());
+        return (processDecline(decline, context));
+    }
+
     using Dhcpv6Srv::processSolicit;
     using Dhcpv6Srv::processRequest;
     using Dhcpv6Srv::processRenew;
index be61642d1f3fbd8eddef155e42098819668680d0..a3ba0e2339c38113e6e1db0309be3215a576358b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -7,6 +7,7 @@
 #include <config.h>
 
 #include <asiolink/io_address.h>
+#include <asiolink/io_service.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/duid.h>
 #include <dhcp6/json_config_parser.h>
@@ -22,6 +23,7 @@
 
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp6/tests/dhcp6_client.h>
+#include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcp/tests/pkt_captures.h>
 #include <cc/command_interpreter.h>
@@ -53,16 +55,17 @@ TEST_F(Dhcpv6SrvTest, Hooks) {
     NakedDhcpv6Srv srv(0);
 
     // check if appropriate hooks are registered
-    int hook_index_buffer6_receive  = -1;
-    int hook_index_buffer6_send     = -1;
-    int hook_index_lease6_renew     = -1;
-    int hook_index_lease6_release   = -1;
-    int hook_index_lease6_rebind    = -1;
-    int hook_index_lease6_decline   = -1;
-    int hook_index_pkt6_received    = -1;
-    int hook_index_select_subnet    = -1;
-    int hook_index_pkt6_send        = -1;
-    int hook_index_host6_identifier = -1;
+    int hook_index_buffer6_receive   = -1;
+    int hook_index_buffer6_send      = -1;
+    int hook_index_lease6_renew      = -1;
+    int hook_index_lease6_release    = -1;
+    int hook_index_lease6_rebind     = -1;
+    int hook_index_lease6_decline    = -1;
+    int hook_index_pkt6_received     = -1;
+    int hook_index_select_subnet     = -1;
+    int hook_index_leases6_committed = -1;
+    int hook_index_pkt6_send         = -1;
+    int hook_index_host6_identifier  = -1;
 
     // check if appropriate indexes are set
     EXPECT_NO_THROW(hook_index_buffer6_receive = ServerHooks::getServerHooks()
@@ -81,22 +84,25 @@ TEST_F(Dhcpv6SrvTest, Hooks) {
                     .getIndex("pkt6_receive"));
     EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
                     .getIndex("subnet6_select"));
-    EXPECT_NO_THROW(hook_index_pkt6_send     = ServerHooks::getServerHooks()
+    EXPECT_NO_THROW(hook_index_leases6_committed = ServerHooks::getServerHooks()
+                    .getIndex("leases6_committed"));
+    EXPECT_NO_THROW(hook_index_pkt6_send = ServerHooks::getServerHooks()
                     .getIndex("pkt6_send"));
     EXPECT_NO_THROW(hook_index_host6_identifier = ServerHooks::getServerHooks()
                     .getIndex("host6_identifier"));
 
 
-    EXPECT_TRUE(hook_index_pkt6_received   > 0);
-    EXPECT_TRUE(hook_index_select_subnet   > 0);
-    EXPECT_TRUE(hook_index_pkt6_send       > 0);
-    EXPECT_TRUE(hook_index_buffer6_receive > 0);
-    EXPECT_TRUE(hook_index_buffer6_send    > 0);
-    EXPECT_TRUE(hook_index_lease6_renew    > 0);
-    EXPECT_TRUE(hook_index_lease6_release  > 0);
-    EXPECT_TRUE(hook_index_lease6_rebind   > 0);
-    EXPECT_TRUE(hook_index_lease6_decline  > 0);
-    EXPECT_TRUE(hook_index_host6_identifier > 0);
+    EXPECT_TRUE(hook_index_pkt6_received     > 0);
+    EXPECT_TRUE(hook_index_select_subnet     > 0);
+    EXPECT_TRUE(hook_index_leases6_committed > 0);
+    EXPECT_TRUE(hook_index_pkt6_send         > 0);
+    EXPECT_TRUE(hook_index_buffer6_receive   > 0);
+    EXPECT_TRUE(hook_index_buffer6_send      > 0);
+    EXPECT_TRUE(hook_index_lease6_renew      > 0);
+    EXPECT_TRUE(hook_index_lease6_release    > 0);
+    EXPECT_TRUE(hook_index_lease6_rebind     > 0);
+    EXPECT_TRUE(hook_index_lease6_decline    > 0);
+    EXPECT_TRUE(hook_index_host6_identifier  > 0);
 }
 
 /// @brief a class dedicated to Hooks testing in DHCPv6 server
@@ -120,6 +126,8 @@ public:
         // Clear static buffers
         resetCalloutBuffers();
 
+        io_service_ = boost::make_shared<IOService>();
+
         // Reset the hook system in its original state
         HooksManager::unloadLibraries();
     }
@@ -750,6 +758,76 @@ public:
         return (lease6_decline_callout(callout_handle));
     }
 
+    /// Test callback that stores values passed to leases6_committed.
+    static int
+    leases6_committed_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("leases6_committed");
+
+        callout_handle.getArgument("query6", callback_qry_pkt6_);
+
+        Lease6CollectionPtr leases6;
+        callout_handle.getArgument("leases6", leases6);
+        if (leases6->size() > 0) {
+            callback_lease6_ = leases6->at(0);
+        }
+
+        Lease6CollectionPtr deleted_leases6;
+        callout_handle.getArgument("deleted_leases6", deleted_leases6);
+        if (deleted_leases6->size() > 0) {
+            callback_deleted_lease6_ = deleted_leases6->at(0);
+        }
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        sort(callback_argument_names_.begin(), callback_argument_names_.end());
+
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
+        return (0);
+    }
+
+    static void
+    leases6_committed_unpark(ParkingLotHandlePtr parking_lot, Pkt6Ptr query) {
+        parking_lot->unpark(query);
+    }
+
+    /// Test callback which asks the server to park the packet.
+    static int
+    leases6_committed_park_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("leases6_committed");
+
+        callout_handle.getArgument("query6", callback_qry_pkt6_);
+
+        io_service_->post(boost::bind(&HooksDhcpv6SrvTest::leases6_committed_unpark,
+                                      callout_handle.getParkingLotHandlePtr(),
+                                      callback_qry_pkt6_));
+
+        callout_handle.getParkingLotHandlePtr()->reference(callback_qry_pkt6_);
+        callout_handle.setStatus(CalloutHandle::NEXT_STEP_PARK);
+
+        Lease6CollectionPtr leases6;
+        callout_handle.getArgument("leases6", leases6);
+        if (leases6->size() > 0) {
+            callback_lease6_ = leases6->at(0);
+        }
+
+        Lease6CollectionPtr deleted_leases6;
+        callout_handle.getArgument("deleted_leases6", deleted_leases6);
+        if (deleted_leases6->size() > 0) {
+            callback_deleted_lease6_ = deleted_leases6->at(0);
+        }
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        sort(callback_argument_names_.begin(), callback_argument_names_.end());
+
+        if (callback_qry_pkt6_) {
+            callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+        }
+
+        return (0);
+    }
+
     /// @brief Test host6_identifier by setting identifier to "foo"
     ///
     /// @param callout_handle handle passed by the hooks framework
@@ -777,7 +855,7 @@ public:
         return (0);
     }
 
-    /// @brief Test host4_identifier callout by setting identifier to hwaddr
+    /// @brief Test host6_identifier callout by setting identifier to hwaddr
     ///
     /// This callout always returns fixed HWADDR: 00:01:02:03:04:05
     ///
@@ -814,6 +892,7 @@ public:
         callback_resp_pkt6_.reset();
         callback_subnet6_.reset();
         callback_lease6_.reset();
+        callback_deleted_lease6_.reset();
         callback_ia_na_.reset();
         callback_subnet6collection_ = NULL;
         callback_argument_names_.clear();
@@ -824,6 +903,9 @@ public:
     /// Pointer to Dhcpv6Srv that is used in tests
     boost::scoped_ptr<NakedDhcpv6Srv> srv_;
 
+    /// Pointer to the IO service used in the tests.
+    static IOServicePtr io_service_;
+
     // The following fields are used in testing pkt6_receive_callout
 
     /// String name of the received callout
@@ -835,9 +917,12 @@ public:
     /// Server's response Pkt6 structure returned in the callout
     static Pkt6Ptr callback_resp_pkt6_;
 
-    /// Pointer to lease6
+    /// Pointer to lease6 structure returned in the leases8_committed callout
     static Lease6Ptr callback_lease6_;
 
+    /// Pointer to lease6 structure returned in the leases8_committed callout
+    static Lease6Ptr callback_deleted_lease6_;
+
     /// Pointer to IA_NA option being renewed or rebound
     static boost::shared_ptr<Option6IA> callback_ia_na_;
 
@@ -869,6 +954,7 @@ const uint32_t HooksDhcpv6SrvTest::override_valid_ = 1004;
 
 // The following fields are used in testing pkt6_receive_callout.
 // See fields description in the class for details
+IOServicePtr HooksDhcpv4SrvTest::io_service_;
 string HooksDhcpv6SrvTest::callback_name_;
 Pkt6Ptr HooksDhcpv6SrvTest::callback_qry_pkt6_;
 Pkt6Ptr HooksDhcpv6SrvTest::callback_resp_pkt6_;
@@ -876,6 +962,7 @@ Subnet6Ptr HooksDhcpv6SrvTest::callback_subnet6_;
 const Subnet6Collection* HooksDhcpv6SrvTest::callback_subnet6collection_;
 vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
 Lease6Ptr HooksDhcpv6SrvTest::callback_lease6_;
+Lease6Ptr HooksDhcpv6SrvTest::callback_deleted_lease6_;
 boost::shared_ptr<Option6IA> HooksDhcpv6SrvTest::callback_ia_na_;
 bool HooksDhcpv6SrvTest::callback_qry_options_copy_;
 bool HooksDhcpv6SrvTest::callback_resp_options_copy_;
@@ -907,11 +994,13 @@ public:
         // Get rid of any marker files.
         static_cast<void>(remove(LOAD_MARKER_FILE));
         static_cast<void>(remove(UNLOAD_MARKER_FILE));
+        static_cast<void>(remove(SRV_CONFIG_MARKER_FILE));
 
         CfgMgr::instance().clear();
     }
 };
 
+
 // Checks if callouts installed on buffer6_receive are indeed called and the
 // all necessary parameters are passed.
 //
index d279aac10c2627873eb71349d706258435077694..06f60d85ae802829e13f081304c79eee49bf6149 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -14,6 +14,7 @@
 namespace {
 const char* const LOAD_MARKER_FILE = "@abs_builddir@/load_marker.txt";
 const char* const UNLOAD_MARKER_FILE = "@abs_builddir@/unload_marker.txt";
+const char* const SRV_CONFIG_MARKER_FILE = "@abs_builddir@/srv_config_marker_file.txt";
 }
 
 namespace isc {
index 9a54fc65a2aeaeeb50eb8b16f60f51b61ae612da..e307d86c3b1dee9c3fc3bb63006a525e7cbc301e 100644 (file)
@@ -19,6 +19,7 @@ namespace {
 // operation.
 const char* const CALLOUT_LIBRARY_1 = "@abs_builddir@/.libs/libco1.so";
 const char* const CALLOUT_LIBRARY_2 = "@abs_builddir@/.libs/libco2.so";
+const char* const CALLOUT_LIBRARY_3 = "@abs_builddir@/.libs/libco3.so";
 
 // Name of a library which is not present.
 const char* const NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere.so";