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.
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 {
}
}
+// 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 {
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) {
// 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();
}
selector.interface_id_ =
query6->getAnyRelayOption(D6O_INTERFACE_ID,
- Pkt6::RELAY_GET_FIRST);
+ Pkt6::RELAY_GET_FIRST);
}
CfgMgr& cfgmgr = CfgMgr::instance();
// 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
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
// 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
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
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
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
// 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
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,
/// @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);
/// @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
#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 {
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;
}
// 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
/// 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
// 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>
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
+using namespace isc::hooks;
using namespace isc::util;
namespace {
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
/// 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.
/// @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.
};
+Pkt4Ptr Dhcp4to6IpcTest::callback_recv_pkt_;
+Pkt4Ptr Dhcp4to6IpcTest::callback_sent_pkt_;
+
void
Dhcp4to6IpcTest::configurePort(uint16_t port) {
CfgMgr::instance().getStagingCfg()->setDhcp4o6Port(port);
// 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.
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);
// 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.
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.
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