Browse Source

[4110a] Ported previous code + a lot of improvements (but still things to do)

Francis Dupont 9 years ago
parent
commit
cbdcd2a80e

+ 35 - 0
src/bin/dhcp4/dhcp4_messages.mes

@@ -198,6 +198,41 @@ detected as a duplicate (i.e. another device in the network is using this addres
 However, the server does not have a record for this address. This may indicate
 a client's error or a server's purged database.
 
+% DHCP4_DHCP4O6_BAD_PACKET received malformed DHCPv4o6 packet: %1
+A malformed DHCPv4o6 packet was received.
+
+% DHCP6_DHCP4O6_PACKET_RECEIVED received DHCPv4o6 packet from DHCPv6 server (type %1) for %2 on interface %3
+This debug message is printed when the server is receiving a DHCPv4o6
+from the DHCPv6 server over inter-process communication.
+
+% DHCP4_DHCP4O6_PACKET_SEND %1: trying to send packet %2 (type %3) to %4 on interface %5 encapsulating %6 %7 (type %8)
+The arguments specify the client identification information (HW address
+and client identifier), DHCP message name and type, source IPv4
+address and port, destination IPv4 address and port and the
+interface name.
+
+% DHCP4_DHCP4O6_PACKET_SEND_FAIL %1: failed to send DHCPv4o6 packet: %2
+This error is output if the IPv4 DHCP server fails to send an
+DHCPv4o6 message to the IPv6 DHCP server. The reason for the
+error is included in the message.
+
+% DHCP4_DHCP4O6_RECEIVE_FAIL failed to receive DHCPv4o6: %1
+This debug message indicates the inter-process communication with the
+DHCPv6 server failed. The reason for the error is included in
+the message.
+
+% DHCP4_DHCP4O6_RECEIVING receiving DHCPv4o6 packet from DHCPv6 server
+This debug message is printed when the server is receiving a DHCPv4o6
+from the DHCPv6 server over inter-process communication socket.
+
+% DHCP4_DHCP4O6_RESPONSE_DATA %1: responding with packet %2 (type %3), packet details: %4
+A debug message including the detailed data about the packet being
+sent to the DHCPv6 server to be forwarded to the client. The first
+argument contains the client and the transaction identification
+information. The second and third argument contains the packet name
+and type respectively. The fourth argument contains detailed packet
+information.
+
 % DHCP4_DISCOVER_CLASS_PROCESSING_FAILED %1: client class specific processing failed for DHCPDISCOVER
 This debug message means that the server processing that is unique for each
 client class has reported a failure. The response packet will not be sent.

+ 30 - 46
src/bin/dhcp4/dhcp4_srv.cc

@@ -70,34 +70,6 @@ using namespace isc::log;
 using namespace isc::stats;
 using namespace std;
 
-/// Structure that holds registered hook indexes
-struct Dhcp4Hooks {
-    int hook_index_buffer4_receive_;///< index for "buffer4_receive" hook point
-    int hook_index_pkt4_receive_;   ///< index for "pkt4_receive" hook point
-    int hook_index_subnet4_select_; ///< index for "subnet4_select" hook point
-    int hook_index_lease4_release_; ///< index for "lease4_release" hook point
-    int hook_index_pkt4_send_;      ///< index for "pkt4_send" hook point
-    int hook_index_buffer4_send_;   ///< index for "buffer4_send" hook point
-    int hook_index_lease4_decline_; ///< index for "lease4_decline" hook point
-
-    /// Constructor that registers hook points for DHCPv4 engine
-    Dhcp4Hooks() {
-        hook_index_buffer4_receive_= HooksManager::registerHook("buffer4_receive");
-        hook_index_pkt4_receive_   = HooksManager::registerHook("pkt4_receive");
-        hook_index_subnet4_select_ = HooksManager::registerHook("subnet4_select");
-        hook_index_pkt4_send_      = HooksManager::registerHook("pkt4_send");
-        hook_index_lease4_release_ = HooksManager::registerHook("lease4_release");
-        hook_index_buffer4_send_   = HooksManager::registerHook("buffer4_send");
-        hook_index_lease4_decline_ = HooksManager::registerHook("lease4_decline");
-    }
-};
-
-// 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.
-Dhcp4Hooks Hooks;
-
 namespace isc {
 namespace dhcp {
 
@@ -330,13 +302,30 @@ Dhcpv4Exchange::setHostIdentifiers() {
     }
 }
 
+// Static values so instantiated when the module is loaded.
+// As a result, the hook indexes will be defined before any method in this
+// module is called.
+
+int Dhcpv4Srv::hook_index_buffer4_receive_=
+    HooksManager::registerHook("buffer4_receive");
+int Dhcpv4Srv::hook_index_pkt4_receive_ =
+    HooksManager::registerHook("pkt4_receive");
+int Dhcpv4Srv::hook_index_subnet4_select_ =
+    HooksManager::registerHook("subnet4_select");
+int Dhcpv4Srv::hook_index_pkt4_send_ =
+    HooksManager::registerHook("pkt4_send");
+int Dhcpv4Srv::hook_index_lease4_release_ =
+    HooksManager::registerHook("lease4_release");
+int Dhcpv4Srv::hook_index_buffer4_send_ =
+    HooksManager::registerHook("buffer4_send");
+int Dhcpv4Srv::hook_index_lease4_decline_ =
+    HooksManager::registerHook("lease4_decline");
+
 const std::string Dhcpv4Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
 
 Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const bool use_bcast,
                      const bool direct_response_desired)
-    : shutdown_(true), alloc_engine_(), port_(port),
-      use_bcast_(use_bcast), hook_index_pkt4_receive_(-1),
-      hook_index_subnet4_select_(-1), hook_index_pkt4_send_(-1) {
+    : shutdown_(true), alloc_engine_(), port_(port), use_bcast_(use_bcast) {
 
     LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET).arg(port);
     try {
@@ -360,11 +349,6 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const bool use_bcast,
         alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 0,
                                             false /* false = IPv4 */));
 
-        // Register hook points
-        hook_index_pkt4_receive_   = Hooks.hook_index_pkt4_receive_;
-        hook_index_subnet4_select_ = Hooks.hook_index_subnet4_select_;
-        hook_index_pkt4_send_      = Hooks.hook_index_pkt4_send_;
-
         /// @todo call loadLibraries() when handling configuration changes
 
     } catch (const std::exception &e) {
@@ -576,7 +560,7 @@ Dhcpv4Srv::selectSubnet4o6(const Pkt4Ptr& query) const {
     // Handle a DHCPv6 relayed query
     Pkt4o6Ptr query4o6 = boost::dynamic_pointer_cast<Pkt4o6>(query);
     if (!query4o6) {
-	isc_throw(Unexpected, "Can't get DHCP4o6 message");
+        isc_throw(Unexpected, "Can't get DHCP4o6 message");
     }
     const Pkt6Ptr& query6 = query4o6->getPkt6();
 
@@ -591,7 +575,7 @@ Dhcpv4Srv::selectSubnet4o6(const Pkt4Ptr& query) const {
         }
         selector.interface_id_ =
             query6->getAnyRelayOption(D6O_INTERFACE_ID,
-				      Pkt6::RELAY_GET_FIRST);
+                                      Pkt6::RELAY_GET_FIRST);
     }
 
     CfgMgr& cfgmgr = CfgMgr::instance();
@@ -762,7 +746,7 @@ Dhcpv4Srv::run_one() {
         // Option objects modification does not make sense anymore. Hooks
         // can only manipulate wire buffer at this stage.
         // Let's execute all callouts registered for buffer4_send
-        if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_send_)) {
+        if (HooksManager::calloutsPresent(hook_index_buffer4_send_)) {
             CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
             // Delete previously set arguments
@@ -772,7 +756,7 @@ Dhcpv4Srv::run_one() {
             callout_handle->setArgument("response4", rsp);
 
             // Call callouts
-            HooksManager::callCallouts(Hooks.hook_index_buffer4_send_,
+            HooksManager::callCallouts(hook_index_buffer4_send_,
                                        *callout_handle);
 
             // Callouts decided to skip the next processing step. The next
@@ -831,7 +815,7 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
 
     // The packet has just been received so contains the uninterpreted wire
     // data; execute callouts registered for buffer4_receive.
-    if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_receive_)) {
+    if (HooksManager::calloutsPresent(hook_index_buffer4_receive_)) {
         CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
         // Delete previously set arguments
@@ -841,7 +825,7 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
         callout_handle->setArgument("query4", query);
 
         // Call callouts
-        HooksManager::callCallouts(Hooks.hook_index_buffer4_receive_,
+        HooksManager::callCallouts(hook_index_buffer4_receive_,
                                    *callout_handle);
 
         // Callouts decided to skip the next processing step. The next
@@ -2091,7 +2075,7 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
         bool skip = false;
 
         // Execute all callouts registered for lease4_release
-        if (HooksManager::calloutsPresent(Hooks.hook_index_lease4_release_)) {
+        if (HooksManager::calloutsPresent(hook_index_lease4_release_)) {
             CalloutHandlePtr callout_handle = getCalloutHandle(release);
 
             // Delete all previous arguments
@@ -2104,7 +2088,7 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
             callout_handle->setArgument("lease4", lease);
 
             // Call all installed callouts
-            HooksManager::callCallouts(Hooks.hook_index_lease4_release_,
+            HooksManager::callCallouts(hook_index_lease4_release_,
                                        *callout_handle);
 
             // Callouts decided to skip the next processing step. The next
@@ -2234,7 +2218,7 @@ Dhcpv4Srv::declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline) {
     // Let's check if there are hooks installed for decline4 hook point.
     // If they are, let's pass the lease and client's packet. If the hook
     // sets status to drop, we reject this Decline.
-    if (HooksManager::calloutsPresent(Hooks.hook_index_lease4_decline_)) {
+    if (HooksManager::calloutsPresent(hook_index_lease4_decline_)) {
         CalloutHandlePtr callout_handle = getCalloutHandle(decline);
 
         // Delete previously set arguments
@@ -2245,7 +2229,7 @@ Dhcpv4Srv::declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline) {
         callout_handle->setArgument("query4", decline);
 
         // Call callouts
-        HooksManager::callCallouts(Hooks.hook_index_lease4_decline_,
+        HooksManager::callCallouts(hook_index_lease4_decline_,
                                    *callout_handle);
 
         // Check if callouts decided to drop the packet. If any of them did,

+ 27 - 6
src/bin/dhcp4/dhcp4_srv.h

@@ -790,6 +790,12 @@ private:
     /// @return Option that contains netmask information
     static OptionPtr getNetmaskOption(const Subnet4Ptr& subnet);
 
+    uint16_t port_;  ///< UDP port number on which server listens.
+    bool use_bcast_; ///< Should broadcast be enabled on sockets (if true).
+
+public:
+    /// Class methods and variables for DHCPv4-over-DHCPv6 handler
+
     /// @brief Updates statistics for received packets
     /// @param query packet received
     static void processStatsReceived(const Pkt4Ptr& query);
@@ -798,13 +804,28 @@ private:
     /// @param query packet transmitted
     static void processStatsSent(const Pkt4Ptr& response);
 
-    uint16_t port_;  ///< UDP port number on which server listens.
-    bool use_bcast_; ///< Should broadcast be enabled on sockets (if true).
-
     /// Indexes for registered hook points
-    int hook_index_pkt4_receive_;
-    int hook_index_subnet4_select_;
-    int hook_index_pkt4_send_;
+
+    /// @brief index for "buffer4_receive" hook point
+    static int hook_index_buffer4_receive_;
+
+    /// @brief index for "pkt4_receive" hook point
+    static int hook_index_pkt4_receive_;
+
+    /// @brief index for "subnet4_select" hook point
+    static int hook_index_subnet4_select_;
+
+    /// @brief index for "lease4_release" hook point
+    static int hook_index_lease4_release_;
+
+    /// @brief index for "pkt4_send" hook point
+    static int hook_index_pkt4_send_;
+
+    /// @brief index for "buffer4_send" hook point
+    static int hook_index_buffer4_send_;
+
+    /// @brief index for "lease4_decline" hook point
+    static int hook_index_lease4_decline_;
 };
 
 }; // namespace isc::dhcp

+ 116 - 17
src/bin/dhcp4/dhcp4to6_ipc.cc

@@ -8,10 +8,21 @@
 
 #include <util/buffer.h>
 #include <dhcp/iface_mgr.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/pkt4o6.h>
+#include <dhcp/pkt6.h>
+#include <dhcpsrv/callout_handle_store.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/dhcp4to6_ipc.h>
+#include <dhcp4/dhcp4_log.h>
+#include <hooks/callout_handle.h>
+#include <hooks/hooks_log.h>
+#include <hooks/hooks_manager.h>
 
 using namespace std;
+using namespace isc::dhcp;
+using namespace isc::hooks;
 
 namespace isc {
 namespace dhcp {
@@ -44,13 +55,25 @@ void Dhcp4to6Ipc::open() {
 
 void Dhcp4to6Ipc::handler() {
     Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
+    Pkt6Ptr pkt;
+
+    try {
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_RECEIVING);
+        // Receive message from the IPC socket.
+        pkt = ipc.receive();
+
+        // from Dhcpv4Srv::run_one() after receivePacket()
+        if (pkt) {
+            LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP6_DHCP4O6_PACKET_RECEIVED)
+                .arg(static_cast<int>(pkt->getType()))
+                .arg(pkt->getRemoteAddr().toText())
+                .arg(pkt->getIface());
+        }
+    } catch (const std::exception& e) {
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_RECEIVE_FAIL)
+            .arg(e.what());
+    }
 
-    // Reset received message in case we return from this method before the
-    // received message pointer is updated.
-    ipc.received_.reset();
-
-    // Receive message from the IPC socket.
-    Pkt6Ptr pkt = ipc.receive();
     if (!pkt) {
         return;
     }
@@ -58,25 +81,101 @@ void Dhcp4to6Ipc::handler() {
     // Each message must contain option holding DHCPv4 message.
     OptionCollection msgs = pkt->getOptions(D6O_DHCPV4_MSG);
     if (msgs.empty()) {
-        isc_throw(Dhcp4o6IpcError, "DHCPv4 message option not present in the"
-                  " DHCPv4o6 message received by the DHCPv4 server");
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_BAD_PACKET)
+            .arg("DHCPv4 message option not present");
+        return;
     } else if (msgs.size() > 1) {
-        isc_throw(Dhcp4o6IpcError, "expected exactly one DHCPv4 message within"
-                  " DHCPv4 message option received by the DHCPv4 server");
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_BAD_PACKET)
+            .arg("more than one DHCPv4 message option");
+        return;
     }
 
+    // Get the DHCPv4 message 
     OptionPtr msg = msgs.begin()->second;
     if (!msg) {
-        isc_throw(Dhcp4o6IpcError, "null DHCPv4 message option in the"
-                  " DHCPv4o6 message received by the DHCPv4 server");
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_BAD_PACKET)
+            .arg("null DHCPv4 message option");
+        return;
     }
 
-    // Record this message.
-    ipc.received_.reset(new Pkt4o6(msg->getData(), pkt));
-}
+    // Extract the DHCPv4 packet with DHCPv6 packet attached
+    Pkt4Ptr query(new Pkt4o6(msg->getData(), pkt));
 
-Pkt4o6Ptr& Dhcp4to6Ipc::getReceived() {
-    return (received_);
+    // From Dhcpv4Srv::run_one() processing and after
+    Pkt4Ptr rsp;
+
+    ControlledDhcpv4Srv::getInstance()->processPacket(query, 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 buffer4_send
+        if (HooksManager::calloutsPresent(Dhcpv4Srv::hook_index_buffer4_send_)) {
+            CalloutHandlePtr callout_handle = getCalloutHandle(query);
+
+            // Delete previously set arguments
+            callout_handle->deleteAllArguments();
+
+            // Pass incoming packet as argument
+            callout_handle->setArgument("response4", rsp);
+
+            // Call callouts
+            HooksManager::callCallouts(Dhcpv4Srv::hook_index_buffer4_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) {
+                LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
+                          DHCP4_HOOK_BUFFER_SEND_SKIP)
+                    .arg(rsp->getLabel());
+                return;
+            }
+
+            /// @todo: Add support for DROP status.
+
+            callout_handle->getArgument("response4", rsp);
+        }
+
+        Pkt4o6Ptr rsp6 = boost::dynamic_pointer_cast<Pkt4o6>(rsp);
+        // Should not happen
+        if (!rsp6) {
+            isc_throw(Unexpected, "Dhcp4o6 packet cast fail");
+        }
+
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_DHCP4O6_PACKET_SEND)
+            .arg(rsp6->getLabel())
+            .arg(rsp6->getName())
+            .arg(static_cast<int>(rsp6->getType()))
+            .arg(rsp6->getRemoteAddr())
+            .arg(rsp6->getIface())
+            .arg(rsp->getLabel())
+            .arg(rsp->getName())
+            .arg(static_cast<int>(rsp->getType()));
+
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA,
+                  DHCP4_DHCP4O6_RESPONSE_DATA)
+            .arg(rsp6->getLabel())
+            .arg(rsp6->getName())
+            .arg(static_cast<int>(rsp6->getType()))
+            .arg(rsp6->toText());
+
+        ipc.send(rsp6->getPkt6());
+
+        // Update statistics accordingly for sent packet.
+        Dhcpv4Srv::processStatsSent(rsp);
+
+    } catch (const std::exception& e) {
+        LOG_ERROR(packet4_logger, DHCP4_DHCP4O6_PACKET_SEND_FAIL)
+            .arg(rsp->getLabel())
+            .arg(e.what());
+    }
 }
 
 };  // namespace dhcp

+ 0 - 10
src/bin/dhcp4/dhcp4to6_ipc.h

@@ -48,16 +48,6 @@ public:
     /// The handler processes the DHCPv4-query DHCPv6 packet and
     /// sends the DHCPv4-response DHCPv6 packet back to the DHCPv6 server
     static void handler();
-
-    /// @brief Returns last received packet
-    ///
-    /// @return a reference to a shared pointer to the last received packet
-    /// @note This reference should be cleared after use
-    Pkt4o6Ptr& getReceived();
-
-private:
-    /// @brief last received packet
-    Pkt4o6Ptr received_;
 };
 
 } // namespace isc

+ 158 - 9
src/bin/dhcp4/tests/dhcp4to6_ipc_unittest.cc

@@ -5,13 +5,19 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 #include <config.h>
+
 #include <asiolink/io_address.h>
 #include <dhcp/pkt4o6.h>
 #include <dhcp/pkt6.h>
 #include <dhcp/tests/iface_mgr_test_config.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/dhcp4to6_ipc.h>
+#include <dhcp4/tests/dhcp4_test_utils.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/testutils/dhcp4o6_test_ipc.h>
+#include <hooks/callout_handle.h>
+#include <hooks/hooks_manager.h>
+
 #include <gtest/gtest.h>
 #include <stdint.h>
 
@@ -19,6 +25,7 @@ using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
+using namespace isc::hooks;
 using namespace isc::util;
 
 namespace {
@@ -30,7 +37,7 @@ const uint16_t TEST_PORT = 32000;
 typedef Dhcp4o6TestIpc TestIpc;
 
 /// @brief Test fixture class for DHCPv4 endpoint of DHCPv4o6 IPC.
-class Dhcp4to6IpcTest : public ::testing::Test {
+class Dhcp4to6IpcTest : public Dhcpv4SrvTest {
 public:
 
     /// @brief Constructor
@@ -38,8 +45,16 @@ public:
     /// Configures IPC to use a test port. It also provides a fake
     /// configuration of interfaces.
     Dhcp4to6IpcTest()
-        : iface_mgr_test_config_(true) {
+	: Dhcpv4SrvTest(),
+	iface_mgr_test_config_(true) {
         configurePort(TEST_PORT);
+	// Install buffer4_receive_callout
+	EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().
+			registerCallout("buffer4_receive",
+					buffer4_receive_callout));
+        // Install buffer4_send_callout
+        EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().
+                        registerCallout("buffer4_send", buffer4_send_callout));
     }
 
     /// @brief Configure DHCP4o6 port.
@@ -55,6 +70,42 @@ public:
     /// @return Pointer to the instance of the DHCPv4-query Message option.
     OptionPtr createDHCPv4MsgOption() const;
 
+    /// @brief Handler for the buffer4_receive hook
+    ///
+    /// This hook is at the beginning of processPacket
+    ///
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+        buffer4_receive_callout(CalloutHandle& callout_handle) {
+        callout_handle.getArgument("query4", callback_recv_pkt_);
+        return (0);
+    }
+
+    /// @brief Handler for the buffer4_send hook
+    ///
+    /// This hook is at the end of the DHCPv4o6 packet handler
+    ///
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+        buffer4_send_callout(CalloutHandle& callout_handle) {
+        callout_handle.getArgument("response4", callback_sent_pkt_);
+        return (0);
+    }
+
+    /// @brief Response Pkt4 shared pointer returned in the receive callout
+    static Pkt4Ptr callback_recv_pkt_;
+
+    /// @brief Response Pkt4 shared pointer returned in the send callout
+    static Pkt4Ptr callback_sent_pkt_;
+
+    /// @brief reference to a controlled server
+    ///
+    /// Dhcp4to6Ipc::handler() uses the instance of the controlled server
+    /// so it has to be build. This reference does this.
+    ControlledDhcpv4Srv srv;
+
 private:
 
     /// @brief Provides fake configuration of interfaces.
@@ -62,6 +113,9 @@ private:
 
 };
 
+Pkt4Ptr Dhcp4to6IpcTest::callback_recv_pkt_;
+Pkt4Ptr Dhcp4to6IpcTest::callback_sent_pkt_;
+
 void
 Dhcp4to6IpcTest::configurePort(uint16_t port) {
     CfgMgr::instance().getStagingCfg()->setDhcp4o6Port(port);
@@ -94,6 +148,11 @@ TEST_F(Dhcp4to6IpcTest, invalidPortError) {
 // This test verifies that the DHCPv4 endpoint of the DHCPv4o6 IPC can
 // receive messages.
 TEST_F(Dhcp4to6IpcTest, receive) {
+    // Verify we have a controlled server
+    ControlledDhcpv4Srv* srv = NULL;
+    ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
+    ASSERT_TRUE(srv);
+
     // Create instance of the IPC endpoint under test.
     Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
     // Create instance of the IPC endpoint being used as a source of messages.
@@ -110,12 +169,20 @@ TEST_F(Dhcp4to6IpcTest, receive) {
     pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
     ASSERT_NO_THROW(pkt->pack());
 
+    // Reset the received packet
+    Dhcp4to6IpcTest::callback_recv_pkt_.reset();
+
     // Send and wait up to 1 second to receive it.
     ASSERT_NO_THROW(src_ipc.send(pkt));
     ASSERT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
 
     // Make sure that the message has been received.
-    Pkt4o6Ptr pkt_received = ipc.getReceived();
+    // The buffer4_receive hook is at the beginning of processPacket
+    // so this proves it was passed to it.
+    Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_;
+    ASSERT_TRUE(pkt4_received);
+    Pkt4o6Ptr pkt_received =
+        boost::dynamic_pointer_cast<Pkt4o6>(pkt4_received);
     ASSERT_TRUE(pkt_received);
     Pkt6Ptr pkt6_received = pkt_received->getPkt6();
     ASSERT_TRUE(pkt6_received);
@@ -126,6 +193,11 @@ TEST_F(Dhcp4to6IpcTest, receive) {
 // This test verifies that message with multiple DHCPv4 query options
 // is rejected.
 TEST_F(Dhcp4to6IpcTest, receiveMultipleQueries) {
+    // Verify we have a controlled server
+    ControlledDhcpv4Srv* srv = NULL;
+    ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
+    ASSERT_TRUE(srv);
+
     // Create instance of the IPC endpoint under test.
     Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
     // Create instance of the IPC endpoint being used as a source of messages.
@@ -144,14 +216,25 @@ TEST_F(Dhcp4to6IpcTest, receiveMultipleQueries) {
     pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
     ASSERT_NO_THROW(pkt->pack());
 
-    // Send message.
+    // Reset the received packet
+    Dhcp4to6IpcTest::callback_recv_pkt_.reset();
+
+    // Send and wait up to 1 second to receive it.
     ASSERT_NO_THROW(src_ipc.send(pkt));
-    // Reception handler should throw exception.
-    EXPECT_THROW(IfaceMgr::instance().receive6(1, 0), Dhcp4o6IpcError);
+    EXPECT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
+
+    // No message should has been sent.
+    Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_;
+    EXPECT_FALSE(pkt4_received);
 }
 
 // This test verifies that message with no DHCPv4 query options is rejected.
 TEST_F(Dhcp4to6IpcTest, receiveNoQueries) {
+    // Verify we have a controlled server
+    ControlledDhcpv4Srv* srv = NULL;
+    ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
+    ASSERT_TRUE(srv);
+
     // Create instance of the IPC endpoint under test.
     Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
     // Create instance of the IPC endpoint being used as a source of messages.
@@ -167,10 +250,76 @@ TEST_F(Dhcp4to6IpcTest, receiveNoQueries) {
     pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
     ASSERT_NO_THROW(pkt->pack());
 
-    // Send message.
+    // Reset the received packet
+    Dhcp4to6IpcTest::callback_recv_pkt_.reset();
+
+    // Send and wait up to 1 second to receive it.
+    ASSERT_NO_THROW(src_ipc.send(pkt));
+    EXPECT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
+
+    // No message should has been sent.
+    Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_;
+    EXPECT_FALSE(pkt4_received);
+}
+
+// This test verifies that the DHCPv4 endpoint of the DHCPv4o6 IPC can
+// process messages.
+TEST_F(Dhcp4to6IpcTest, process) {
+    // Verify we have a controlled server
+    ControlledDhcpv4Srv* srv = NULL;
+    ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
+    ASSERT_TRUE(srv);
+
+    // Create instance of the IPC endpoint under test.
+    Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
+    // Create instance of the IPC endpoint being used as a source of messages.
+    TestIpc src_ipc(TEST_PORT, TestIpc::ENDPOINT_TYPE_V6);
+
+    // Open both endpoints.
+    ASSERT_NO_THROW(ipc.open());
+    ASSERT_NO_THROW(src_ipc.open());
+
+    // Create message to be sent over IPC.
+    Pkt6Ptr pkt(new Pkt6(DHCPV6_DHCPV4_QUERY, 1234));
+    pkt->addOption(createDHCPv4MsgOption());
+    pkt->setIface("eth0");
+    pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
+    ASSERT_NO_THROW(pkt->pack());
+
+    // TODO: put enough in the packet and server config to make it pass
+    // through processPacket, in particular provide a subnet to select
+
+    // Reset the received packet
+    Dhcp4to6IpcTest::callback_recv_pkt_.reset();
+
+    // Send and wait up to 1 second to receive it.
     ASSERT_NO_THROW(src_ipc.send(pkt));
-    // Reception handler should throw exception.
-    EXPECT_THROW(IfaceMgr::instance().receive6(1, 0), Dhcp4o6IpcError);
+    ASSERT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
+
+    // Make sure that the message has been received.
+    Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_;
+    ASSERT_TRUE(pkt4_received);
+    Pkt4o6Ptr pkt_received =
+        boost::dynamic_pointer_cast<Pkt4o6>(pkt4_received);
+    ASSERT_TRUE(pkt_received);
+    Pkt6Ptr pkt6_received = pkt_received->getPkt6();
+    ASSERT_TRUE(pkt6_received);
+    EXPECT_EQ("eth0", pkt6_received->getIface());
+    EXPECT_EQ("2001:db8:1::123", pkt6_received->getRemoteAddr().toText());
+
+    // Make sure that the message has been processed.
+    // Using the buffer4_send hook
+    Pkt4Ptr pkt4_sent = Dhcp4to6IpcTest::callback_sent_pkt_;
+#if 0
+    ASSERT_TRUE(pkt4_sent);
+    Pkt4o6Ptr pkt_sent = boost::dynamic_pointer_cast<Pkt4o6>(pkt4_sent);
+    ASSERT_TRUE(pkt_sent);
+    Pkt6Ptr pkt6_sent = pkt_sent->getPkt6();
+    ASSERT_TRUE(pkt6_sent);
+    EXPECT_EQ("eth0", pkt6_sent->getIface());
+    EXPECT_EQ("2001:db8:1::123", pkt6_sent->getRemoteAddr().toText());
+    // more tests
+#endif
 }
 
 } // end of anonymous namespace