Commit 8b0cb0de authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2902] DHCPv4 server will try to use 'direct response' feature if possible.

parent fa9feb90
......@@ -61,8 +61,13 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig, const bool use_bcast)
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET).arg(port);
try {
// First call to instance() will create IfaceMgr (it's a singleton)
// it may throw something if things go wrong
IfaceMgr::instance();
// it may throw something if things go wrong.
// The 'true' value of in the call to setMatchingPacketFilter imposes
// that IfaceMgr will try to use the mechanism to respond directly
// to the client which doesn't have address assigned. This capability
// may be lacking on some OSes, so there is no guarantee that server
// will be able to respond directly.
IfaceMgr::instance().setMatchingPacketFilter(true);
if (port) {
// open sockets only if port is non-zero. Port 0 is used
......
......@@ -157,6 +157,11 @@ IfaceMgr::~IfaceMgr() {
closeSockets();
}
bool
IfaceMgr::isDirectResponseSupported() const {
return (packet_filter_->isDirectResponseSupported());
}
void IfaceMgr::stubDetectIfaces() {
string ifaceName;
const string v4addr("127.0.0.1"), v6addr("::1");
......
......@@ -39,13 +39,6 @@ public:
isc::Exception(file, line, what) { };
};
/// @brief IfaceMgr exception thrown when invalid packet filter object specified.
class InvalidPacketFilter : public Exception {
public:
InvalidPacketFilter(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief IfaceMgr exception thrown thrown when socket opening
/// or configuration failed.
class SocketConfigError : public Exception {
......@@ -324,7 +317,7 @@ public:
/// the client.
///
/// @return true if direct response is supported.
bool isDirectResponseSupported();
bool isDirectResponseSupported() const;
/// @brief Returns interface with specified interface index
///
......@@ -580,6 +573,22 @@ public:
packet_filter_ = packet_filter;
}
/// @brief Set Packet Filter object to handle send/receive packets.
///
/// This function sets Packet Filter object to be used by IfaceMgr,
/// appropriate for the current OS. They will vary depending on the
/// OS being used if the function argument is set 'true'. There is
/// no guarantee that there is an implementation that supports this
/// feature on a particular OS. If there isn't the PktFilterInet
/// object will be set. If the argument is set to 'false' then
/// PktFilterInet object instance will be set as the Packet Filter
/// regrdaless of the OS.
///
/// @param direct_response_desired specifies whether the Packet Filter
/// object being set should support direct responses to the host
/// not having address assigned.
void setMatchingPacketFilter(const bool direct_response_desired = false);
/// A value of socket descriptor representing "not specified" state.
static const int INVALID_SOCKET = -1;
......
......@@ -34,11 +34,6 @@ IfaceMgr::detectIfaces() {
stubDetectIfaces();
}
bool
IfaceMgr::isDirectResponseSupported() {
return (false);
}
void IfaceMgr::os_send4(struct msghdr& /*m*/,
boost::scoped_array<char>& /*control_buf*/,
size_t /*control_buf_len*/,
......@@ -54,6 +49,13 @@ bool IfaceMgr::os_receive4(struct msghdr& /*m*/, Pkt4Ptr& /*pkt*/) {
return (true); // pretend that we have everything set up for reception.
}
void
IfaceMgr::setMatchingPacketFilter(const bool /* direct_response_desired */) {
boost::shared_ptr<PktFilter> pkt_filter(new PktFilterInet());
setPacketFilter(pkt_filter);
}
} // end of isc::dhcp namespace
} // end of dhcp namespace
......
......@@ -33,6 +33,8 @@
#include <asiolink/io_address.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/pkt_filter_inet.h>
#include <dhcp/pkt_filter_lpf.h>
#include <exceptions/exceptions.h>
#include <util/io/sockaddr_util.h>
......@@ -494,11 +496,6 @@ void IfaceMgr::detectIfaces() {
nl.release_list(addr_info);
}
bool
IfaceMgr::isDirectResponseSupported() {
return (false);
}
/// @brief sets flag_*_ fields.
///
/// This implementation is OS-specific as bits have different meaning
......@@ -515,6 +512,18 @@ void Iface::setFlags(uint32_t flags) {
flag_broadcast_ = flags & IFF_BROADCAST;
}
void
IfaceMgr::setMatchingPacketFilter(const bool direct_response_desired) {
if (direct_response_desired) {
boost::shared_ptr<PktFilter> pkt_filter(new PktFilterLPF());
setPacketFilter(pkt_filter);
} else {
boost::shared_ptr<PktFilter> pkt_filter(new PktFilterInet());
setPacketFilter(pkt_filter);
}
}
void IfaceMgr::os_send4(struct msghdr&, boost::scoped_array<char>&,
size_t, const Pkt4Ptr&) {
......
......@@ -34,11 +34,6 @@ IfaceMgr::detectIfaces() {
stubDetectIfaces();
}
bool
IfaceMgr::isDirectResponseSupported() {
return (false);
}
void IfaceMgr::os_send4(struct msghdr& /*m*/,
boost::scoped_array<char>& /*control_buf*/,
size_t /*control_buf_len*/,
......@@ -54,6 +49,12 @@ bool IfaceMgr::os_receive4(struct msghdr& /*m*/, Pkt4Ptr& /*pkt*/) {
return (true); // pretend that we have everything set up for reception.
}
void
IfaceMgr::setMatchingPacketFilter(const bool /* direct_response_desired */) {
boost::shared_ptr<PktFilter> pkt_filter(new PktFilterInet());
setPacketFilter(pkt_filter);
}
} // end of isc::dhcp namespace
} // end of dhcp namespace
......
......@@ -15,12 +15,20 @@
#ifndef PKT_FILTER_H
#define PKT_FILTER_H
#include <dhcp/pkt4.h>
#include <asiolink/io_address.h>
#include <boost/shared_ptr.hpp>
namespace isc {
namespace dhcp {
/// @brief Exception thrown when invalid packet filter object specified.
class InvalidPacketFilter : public Exception {
public:
InvalidPacketFilter(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
struct SocketInfo;
/// Forward declaration to the class representing interface
......@@ -46,6 +54,18 @@ public:
/// @brief Virtual Destructor
virtual ~PktFilter() { }
/// @brief Check if packet can be sent to the host without address directly.
///
/// Checks if the Packet Filter class has capability to send a packet
/// directly to the client having no address assigned. This capability
/// is used by DHCPv4 servers which respond to the clients they assign
/// addresses to. Not all classes derived from PktFilter support this
/// because it requires injection of the destination host HW address to
/// the link layer header of the packet.
///
/// @return true of the direct response is supported.
virtual bool isDirectResponseSupported() const = 0;
/// @brief Open socket.
///
/// @param iface interface descriptor
......
......@@ -33,6 +33,17 @@ public:
/// Allocates control buffer.
PktFilterInet();
/// @brief Check if packet can be sent to the host without address directly.
///
/// This Packet Filter sends packets through AF_INET datagram sockets, so
/// it can't inject the HW address of the destionation host into the packet.
/// Therefore this class does not support direct responses.
///
/// @return false always.
virtual bool isDirectResponseSupported() const {
return (false);
}
/// @brief Open socket.
///
/// @param iface interface descriptor
......
......@@ -32,6 +32,15 @@ namespace dhcp {
class PktFilterLPF : public PktFilter {
public:
/// @brief Check if packet can be sent to the host without address directly.
///
/// This class supports direct responses to the host without address.
///
/// @return true always.
virtual bool isDirectResponseSupported() const {
return (true);
}
/// @brief Open socket.
///
/// @param iface interface descriptor
......
......@@ -74,6 +74,10 @@ public:
: open_socket_called_(false) {
}
virtual bool isDirectResponseSupported() const {
return (false);
}
/// Pretends to open socket. Only records a call to this function.
virtual int openSocket(const Iface&,
const isc::asiolink::IOAddress&,
......@@ -839,6 +843,69 @@ TEST_F(IfaceMgrTest, setPacketFilter) {
EXPECT_EQ(1024, socket1);
}
#if defined OS_LINUX
// This Linux specific test checks whether it is possible to use
// IfaceMgr to figure out which Pakcket Filter object should be
// used when direct responses to hosts, having no address assigned
// are desired or not desired.
TEST_F(IfaceMgrTest, setMatchingPacketFilter) {
// Create an instance of IfaceMgr.
boost::scoped_ptr<NakedIfaceMgr> iface_mgr(new NakedIfaceMgr());
ASSERT_TRUE(iface_mgr);
// Let IfaceMgr figure out which Packet Filter to use when
// direct response capability is not desired. It should pick
// PktFilterInet.
EXPECT_NO_THROW(iface_mgr->setMatchingPacketFilter(false));
// The PktFilterInet is supposed to report lack of direct
// response capability.
EXPECT_FALSE(iface_mgr->isDirectResponseSupported());
// There is working implementation of direct responses on Linux
// in PktFilterLPF. It uses Linux Packet Filtering as underlying
// mechanism. When direct responses are desired the object of
// this class should be set.
EXPECT_NO_THROW(iface_mgr->setMatchingPacketFilter(true));
// This object should report that direct responses are supported.
EXPECT_TRUE(iface_mgr->isDirectResponseSupported());
}
#else
// This non-Linux specific test checks whether it is possible to use
// IfaceMgr to figure out which Pakcket Filter object should be
// used when direct responses to hosts, having no address assigned
// are desired or not desired. Since direct responses aren't supported
// on systems other than Linux the function under test should always
// set object of PktFilterInet type as current Packet Filter. This
// object does not support direct responses. Once implementation is
// added on non-Linux systems the OS specific version of the test
// will be removed.
TEST_F(IfaceMgrTest, setMatchingPacketFilter) {
// Create an instance of IfaceMgr.
boost::scoped_ptr<NakedIfaceMgr> iface_mgr(new NakedIfaceMgr());
ASSERT_TRUE(iface_mgr);
// Let IfaceMgr figure out which Packet Filter to use when
// direct response capability is not desired. It should pick
// PktFilterInet.
EXPECT_NO_THROW(iface_mgr->setMatchingPacketFilter(false));
// The PktFilterInet is supposed to report lack of direct
// response capability.
EXPECT_FALSE(iface_mgr->isDirectResponseSupported());
// On non-Linux systems, we are missing the direct traffic
// implementation. Therefore, we expect that PktFilterInet
// object will be set.
EXPECT_NO_THROW(iface_mgr->setMatchingPacketFilter(true));
// This object should report lack of direct response capability.
EXPECT_FALSE(iface_mgr->isDirectResponseSupported());
}
#endif
TEST_F(IfaceMgrTest, socket4) {
......
......@@ -77,6 +77,17 @@ public:
};
// This test verifies that the PktFilterInet class reports its lack
// of capability to send packets to the host having no IP address
// assigned.
TEST_F(PktFilterInetTest, isDirectResponseSupported) {
// Create object under test.
PktFilterInet pkt_filter;
// This Packet Filter class does not support direct responses
// under any conditions.
EXPECT_FALSE(pkt_filter.isDirectResponseSupported());
}
// This test verifies that the INET datagram socket is correctly opened and
// bound to the appropriate address and port.
TEST_F(PktFilterInetTest, openSocket) {
......
......@@ -81,6 +81,15 @@ public:
};
// This test verifies that the PktFilterLPF class reports its capability
// to send packets to the host having no IP address assigned.
TEST_F(PktFilterLPFTest, isDirectResponseSupported) {
// Create object under test.
PktFilterLPF pkt_filter;
// Must support direct responses.
EXPECT_TRUE(pkt_filter.isDirectResponseSupported());
}
// All tests below require root privileges to execute successfully. If
// they are run as non-root user they will fail due to insufficient privileges
// to open raw network sockets. Therefore, they should remain disabled by default
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment