Commit 924a4f46 authored by Thomas Markwalder's avatar Thomas Markwalder

[#260,!120] Addressed most of review comments

    Addressed all comments except parsing regen and
    refactor of watch sockets in IfaceMgr.  Doing those
    separately.
parent 1f31a082
...@@ -9,13 +9,38 @@ ...@@ -9,13 +9,38 @@
<!-- Converted by db4-upgrade version 1.1 --> <!-- Converted by db4-upgrade version 1.1 -->
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="congestion-handling"> <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="congestion-handling">
<title>Congestion Handling in DHCPv4 and DHCPv6</title> <title>Congestion Handling in DHCPv4 and DHCPv6</title>
<para>Congestion occurs when servers are subjected to client queries
faster than they can be fulfilled. Subsequently, the servers begin
accumulating a backlog of pending queries. The longer the high rate of
traffic continues the farther behind the servers fall. Depending on the
client implementations, those that fail to get leases either give or simply
continue to retry forever. In the former case, the server may eventually
recover. The latter case is vicious cycle from which the server is unable
escape.
</para>
<para>
In a well-planned deployment, the number and capacity of servers is matched
to the maximum client loads expected. As long as capacity is matched to
load, congestion does not occur. If the load is routinely too heavy, then
the deployment needs to be re-evaluated. Congestion typically occurs when
there is a network event that causes overly large numbers of clients to
simultaneously need leases such as recovery after a network outage.
</para>
<para>
The goal of Congestion handling is to help the servers mitigate the peak
in traffic by fulfilling as many of the most relevant requests as possible
until it subsides.
</para>
<para>Prior to Kea 1.5, kea-dhcp4 and kea-dhcp4 read inbound packets directly <para>Prior to Kea 1.5, kea-dhcp4 and kea-dhcp4 read inbound packets directly
from the interface sockets in the main application thread. This meant that from the interface sockets in the main application thread. This meant that
packets waiting to be processed were held in socket buffers themselves. Once packets waiting to be processed were held in socket buffers themselves. Once
these buffers fill any new packets are discarded. Under swamped conditions these buffers fill any new packets are discarded. Under swamped conditions
the servers can end up processing client packets that may no longer be the servers can end up processing client packets that may no longer be
relevant, or worse are redundant. In other words, the packets waiting in relevant, or worse are redundant. In other words, the packets waiting in
the FIFO socket buffers become more and more stale. the FIFO socket buffers become increasingly stale.
</para> </para>
<para>Kea 1.5 introduces a new feature referred to as Congestion Handling. <para>Kea 1.5 introduces a new feature referred to as Congestion Handling.
...@@ -34,13 +59,13 @@ ...@@ -34,13 +59,13 @@
always discarding the newest packets, we now always discard the oldest always discarding the newest packets, we now always discard the oldest
packets. The capacity of the buffer, (i.e the maximum number of packets the packets. The capacity of the buffer, (i.e the maximum number of packets the
buffer can contain) is configurable. A reasonable starting point would be to buffer can contain) is configurable. A reasonable starting point would be to
match the queue size to the number of leases per second your installation of match the capacity to the number of leases per second your installation of
Kea can handle (Please note this figure varies widely depending on your Kea can handle. Please note this figure varies widely depending on the
configuration). We anticipate adding more knobs as we learn from experience, specifics of your deployment. We anticipate adding more knobs as we learn
testing, and user feedback. from experience, testing, and user feedback.
</para> </para>
<para>As there is no one algorithm that will best handle the dynamncis of <para>As there is no one algorithm that will best handle the dynamics of
all sites, and because over time new approaches will evolve, the packet all sites, and because over time new approaches will evolve, the packet
queue is implemented as plug-in, which can replaced by a custom queue queue is implemented as plug-in, which can replaced by a custom queue
implementation via hook library. This should make it straight forward implementation via hook library. This should make it straight forward
...@@ -53,7 +78,6 @@ ...@@ -53,7 +78,6 @@
servers through an optional, top level configuration element, servers through an optional, top level configuration element,
'dhcp-queue-control' (Omitting this element disables packet queueing): 'dhcp-queue-control' (Omitting this element disables packet queueing):
<screen> <screen>
...
"dhcp-queue-control": { "dhcp-queue-control": {
"enable-queue": true|false, "enable-queue": true|false,
"queue-type": "queue type", "queue-type": "queue type",
...@@ -74,9 +98,9 @@ ...@@ -74,9 +98,9 @@
<listitem> <listitem>
<simpara><command>queue-type</command> name of the queue implementation <simpara><command>queue-type</command> name of the queue implementation
to use. This value exists such that custom implementations can be to use. This value exists such that custom implementations can be
registered (via hook lib) and then selected. As mentioned earlier, registered (via hook lib) and then selected. There is a default
there is a default implementation registered: "kea-ring4" for kea-dhcp4 packet queue implementation that is pre-registered during server
and "kea-ring6" for kea-dhcp6. start up: "kea-ring4" for kea-dhcp4 and "kea-ring6" for kea-dhcp6.
</simpara> </simpara>
</listitem> </listitem>
<listitem> <listitem>
...@@ -89,7 +113,7 @@ ...@@ -89,7 +113,7 @@
</itemizedlist> </itemizedlist>
</para> </para>
<para>The following example enables the default packet queue for kea-dhcp4, <para>The following example enables the default packet queue for kea-dhcp4,
with a queue capactiy fo 250 packets: with a queue capacity of 250 packets:
<screen> <screen>
"Dhcp4": "Dhcp4":
{ {
...@@ -104,7 +128,7 @@ ...@@ -104,7 +128,7 @@
</screen> </screen>
</para> </para>
<para> The following example enables the default packet queue for kea-dhcp6, <para> The following example enables the default packet queue for kea-dhcp6,
with a queue capactiy fo 300 packets: with a queue capacity of 300 packets:
<screen> <screen>
"Dhcp6": "Dhcp6":
{ {
......
This diff is collapsed.
...@@ -1849,34 +1849,27 @@ dhcp_queue_control: DHCP_QUEUE_CONTROL { ...@@ -1849,34 +1849,27 @@ dhcp_queue_control: DHCP_QUEUE_CONTROL {
if (!qc->contains("enable-queue")) { if (!qc->contains("enable-queue")) {
std::stringstream msg; std::stringstream msg;
msg << "'enable-queue' is required: "; msg << "'enable-queue' is required: ";
msg << qc->getPosition().str() << ")"; msg << "(" << qc->getPosition().str() << ")";
error(@1, msg.str()); error(@1, msg.str());
} }
ConstElementPtr enable_queue = qc->get("enable-queue"); ConstElementPtr enable_queue = qc->get("enable-queue");
if (enable_queue->getType() != Element::boolean) { if (enable_queue->getType() != Element::boolean) {
std::stringstream msg; std::stringstream msg;
msg << "'enable-queue' must be boolean: "; msg << "'enable-queue' must be boolean: ";
msg << qc->getPosition().str() << ")"; msg << "(" << qc->getPosition().str() << ")";
error(@1, msg.str()); error(@1, msg.str());
} }
if (enable_queue->boolValue()) {
if (!qc->contains("queue-type")) {
std::stringstream msg;
msg << "'queue-type' is required, when 'enable-queue' is true: ";
msg << qc->getPosition().str() << ")";
error(@1, msg.str());
}
if (qc->contains("queue-type")) {
ConstElementPtr queue_type = qc->get("queue-type"); ConstElementPtr queue_type = qc->get("queue-type");
if (queue_type->getType() != Element::string) { if (queue_type->getType() != Element::string) {
std::stringstream msg; std::stringstream msg;
msg << "'queue-type' must be a string: "; msg << "'queue-type' must be a string: ";
msg << qc->getPosition().str() << ")"; msg << "(" << qc->getPosition().str() << ")";
error(@1, msg.str()); error(@1, msg.str());
} }
} }
ctx.leave(); ctx.leave();
}; };
......
...@@ -6591,21 +6591,14 @@ TEST_F(Dhcp4ParserTest, dhcpQueueControlInvalid) { ...@@ -6591,21 +6591,14 @@ TEST_F(Dhcp4ParserTest, dhcpQueueControlInvalid) {
"{ \n" "{ \n"
" \"enable-type\": \"some-type\" \n" " \"enable-type\": \"some-type\" \n"
"} \n", "} \n",
"<string>:2.2-21: 'enable-queue' is required: <string>:2:24)" "<string>:2.2-21: 'enable-queue' is required: (<string>:2:24)"
}, },
{ {
"enable-queue not boolean", "enable-queue not boolean",
"{ \n" "{ \n"
" \"enable-queue\": \"always\" \n" " \"enable-queue\": \"always\" \n"
"} \n", "} \n",
"<string>:2.2-21: 'enable-queue' must be boolean: <string>:2:24)" "<string>:2.2-21: 'enable-queue' must be boolean: (<string>:2:24)"
},
{
"queue enabled, type missing",
"{ \n"
" \"enable-queue\": true \n"
"} \n",
"<string>:2.2-21: 'queue-type' is required, when 'enable-queue' is true: <string>:2:24)"
}, },
{ {
"queue enabled, type not a string", "queue enabled, type not a string",
...@@ -6613,7 +6606,7 @@ TEST_F(Dhcp4ParserTest, dhcpQueueControlInvalid) { ...@@ -6613,7 +6606,7 @@ TEST_F(Dhcp4ParserTest, dhcpQueueControlInvalid) {
" \"enable-queue\": true, \n" " \"enable-queue\": true, \n"
" \"queue-type\": 7777 \n" " \"queue-type\": 7777 \n"
"} \n", "} \n",
"<string>:2.2-21: 'queue-type' must be a string: <string>:2:24)" "<string>:2.2-21: 'queue-type' must be a string: (<string>:2:24)"
} }
}; };
......
This diff is collapsed.
...@@ -1938,35 +1938,29 @@ dhcp_queue_control: DHCP_QUEUE_CONTROL { ...@@ -1938,35 +1938,29 @@ dhcp_queue_control: DHCP_QUEUE_CONTROL {
if (!qc->contains("enable-queue")) { if (!qc->contains("enable-queue")) {
std::stringstream msg; std::stringstream msg;
msg << "'enable-queue' is required: "; msg << "'enable-queue' is required: ";
msg << qc->getPosition().str() << ")"; msg << "(" << qc->getPosition().str() << ")";
error(@1, msg.str()); error(@1, msg.str());
} }
ConstElementPtr enable_queue = qc->get("enable-queue"); // queue-enable is mandatory
if (enable_queue->getType() != Element::boolean) { ConstElementPtr enable_queue = qc->get("enable-queue");
if (enable_queue->getType() != Element::boolean) {
std::stringstream msg; std::stringstream msg;
msg << "'enable-queue' must be boolean: "; msg << "'enable-queue' must be boolean: ";
msg << qc->getPosition().str() << ")"; msg << "(" << qc->getPosition().str() << ")";
error(@1, msg.str()); error(@1, msg.str());
} }
if (enable_queue->boolValue()) { // if queue-type is supplied make sure it's a string
if (!qc->contains("queue-type")) { if (qc->contains("queue-type")) {
std::stringstream msg;
msg << "'queue-type' is required, when 'enable-queue' is true: ";
msg << qc->getPosition().str() << ")";
error(@1, msg.str());
}
ConstElementPtr queue_type = qc->get("queue-type"); ConstElementPtr queue_type = qc->get("queue-type");
if (queue_type->getType() != Element::string) { if (queue_type->getType() != Element::string) {
std::stringstream msg; std::stringstream msg;
msg << "'queue-type' must be a string: "; msg << "'queue-type' must be a string: ";
msg << qc->getPosition().str() << ")"; msg << "(" << qc->getPosition().str() << ")";
error(@1, msg.str()); error(@1, msg.str());
} }
} }
ctx.leave(); ctx.leave();
}; };
......
...@@ -7096,29 +7096,22 @@ TEST_F(Dhcp6ParserTest, dhcpQueueControlInvalid) { ...@@ -7096,29 +7096,22 @@ TEST_F(Dhcp6ParserTest, dhcpQueueControlInvalid) {
"{ \n" "{ \n"
" \"enable-type\": \"some-type\" \n" " \"enable-type\": \"some-type\" \n"
"} \n", "} \n",
"<string>:2.2-21: 'enable-queue' is required: <string>:2:24)" "<string>:2.2-21: 'enable-queue' is required: (<string>:2:24)"
}, },
{ {
"enable-queue not boolean", "enable-queue not boolean",
"{ \n" "{ \n"
" \"enable-queue\": \"always\" \n" " \"enable-queue\": \"always\" \n"
"} \n", "} \n",
"<string>:2.2-21: 'enable-queue' must be boolean: <string>:2:24)" "<string>:2.2-21: 'enable-queue' must be boolean: (<string>:2:24)"
}, },
{ {
"queue enabled, type missing", "queue type not a string",
"{ \n"
" \"enable-queue\": true \n"
"} \n",
"<string>:2.2-21: 'queue-type' is required, when 'enable-queue' is true: <string>:2:24)"
},
{
"queue enabled, type not a string",
"{ \n" "{ \n"
" \"enable-queue\": true, \n" " \"enable-queue\": true, \n"
" \"queue-type\": 7777 \n" " \"queue-type\": 7777 \n"
"} \n", "} \n",
"<string>:2.2-21: 'queue-type' must be a string: <string>:2:24)" "<string>:2.2-21: 'queue-type' must be a string: (<string>:2:24)"
} }
}; };
......
...@@ -78,7 +78,8 @@ const char* EXTRACTED_CONFIGS[] = { ...@@ -78,7 +78,8 @@ const char* EXTRACTED_CONFIGS[] = {
" \"preferred-lifetime\": 3000,\n" " \"preferred-lifetime\": 3000,\n"
" \"rebind-timer\": 2000,\n" " \"rebind-timer\": 2000,\n"
" \"renew-timer\": 1000,\n" " \"renew-timer\": 1000,\n"
" \"subnet6\": [ ],\n" " \"valid-lifetime\": 4000\n" " \"subnet6\": [ ],\n"
" \"valid-lifetime\": 4000\n"
" }\n", " }\n",
// CONFIGURATION 1 // CONFIGURATION 1
"{\n" "{\n"
......
...@@ -1485,8 +1485,12 @@ TestControl::run() { ...@@ -1485,8 +1485,12 @@ TestControl::run() {
isc_throw(InvalidOperation, isc_throw(InvalidOperation,
"command options must be parsed before running a test"); "command options must be parsed before running a test");
} else if (options.getIpVersion() == 4) { } else if (options.getIpVersion() == 4) {
// Turn off packet queueing.
IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, data::ElementPtr());
setTransidGenerator(NumberGeneratorPtr(new SequentialGenerator())); setTransidGenerator(NumberGeneratorPtr(new SequentialGenerator()));
} else { } else {
// Turn off packet queueing.
IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, data::ElementPtr());
setTransidGenerator(NumberGeneratorPtr(new SequentialGenerator(0x00FFFFFF))); setTransidGenerator(NumberGeneratorPtr(new SequentialGenerator(0x00FFFFFF)));
} }
......
...@@ -314,7 +314,6 @@ IfaceMgr::~IfaceMgr() { ...@@ -314,7 +314,6 @@ IfaceMgr::~IfaceMgr() {
// control_buf_ is deleted automatically (scoped_ptr) // control_buf_ is deleted automatically (scoped_ptr)
control_buf_len_ = 0; control_buf_len_ = 0;
stopDHCPReceiver();
closeSockets(); closeSockets();
// Explicitly delete PQM singletons. // Explicitly delete PQM singletons.
...@@ -595,8 +594,9 @@ IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast, ...@@ -595,8 +594,9 @@ IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
} }
} }
// If we have open sockets, start the receiver.
if (count > 0) { if (count > 0) {
// starts the receiver thread (if queueing is enabled); // starts the receiver thread (if queueing is enabled).
startDHCPReceiver(AF_INET); startDHCPReceiver(AF_INET);
} }
...@@ -679,8 +679,9 @@ IfaceMgr::openSockets6(const uint16_t port, ...@@ -679,8 +679,9 @@ IfaceMgr::openSockets6(const uint16_t port,
} }
} }
// If we have open sockets, start the receiver.
if (count > 0) { if (count > 0) {
// starts the receiver thread (if queueing is enabled); // starts the receiver thread (if queueing is enabled).
startDHCPReceiver(AF_INET6); startDHCPReceiver(AF_INET6);
} }
return (count > 0); return (count > 0);
...@@ -694,6 +695,7 @@ IfaceMgr::startDHCPReceiver(const uint16_t family) { ...@@ -694,6 +695,7 @@ IfaceMgr::startDHCPReceiver(const uint16_t family) {
switch (family) { switch (family) {
case AF_INET: case AF_INET:
// If there's no queue, then has been disabled, simply return.
if(!getPacketQueue4()) { if(!getPacketQueue4()) {
return; return;
} }
...@@ -701,6 +703,7 @@ IfaceMgr::startDHCPReceiver(const uint16_t family) { ...@@ -701,6 +703,7 @@ IfaceMgr::startDHCPReceiver(const uint16_t family) {
receiver_thread_.reset(new Thread(boost::bind(&IfaceMgr::receiveDHCP4Packets, this))); receiver_thread_.reset(new Thread(boost::bind(&IfaceMgr::receiveDHCP4Packets, this)));
break; break;
case AF_INET6: case AF_INET6:
// If there's no queue, then has been disabled, simply return.
if(!getPacketQueue6()) { if(!getPacketQueue6()) {
return; return;
} }
...@@ -964,7 +967,7 @@ IfaceMgr::send(const Pkt4Ptr& pkt) { ...@@ -964,7 +967,7 @@ IfaceMgr::send(const Pkt4Ptr& pkt) {
} }
Pkt4Ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) { Pkt4Ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
if (receiver_thread_) { if (isReceiverRunning()) {
return (receive4Indirect(timeout_sec, timeout_usec)); return (receive4Indirect(timeout_sec, timeout_usec));
} }
...@@ -1189,7 +1192,7 @@ Pkt4Ptr IfaceMgr::receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec /* ...@@ -1189,7 +1192,7 @@ Pkt4Ptr IfaceMgr::receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec /*
} }
Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) { Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
if (receiver_thread_) { if (isReceiverRunning()) {
return (receive6Indirect(timeout_sec, timeout_usec)); return (receive6Indirect(timeout_sec, timeout_usec));
} }
......
...@@ -677,56 +677,32 @@ public: ...@@ -677,56 +677,32 @@ public:
/// @return true if sending was successful /// @return true if sending was successful
bool send(const Pkt4Ptr& pkt); bool send(const Pkt4Ptr& pkt);
/// @brief Tries to receive DHCPv6 message over open IPv6 sockets. /// @brief Receive IPv4 packets or data from external sockets
/// ///
/// Attempts to receive a single DHCPv6 message over any of the open IPv6 /// Wrapper around calls to either @c receive4Direct or @c
/// sockets. If reception is successful and all information about its /// receive4Indirect. The former is called when packet queuing is
/// sender is obtained, Pkt6 object is created and returned. /// disabled, the latter when it is enabled.
///
/// This method also checks if data arrived over registered external socket.
/// This data may be of a different protocol family than AF_INET6.
/// ///
/// @param timeout_sec specifies integral part of the timeout (in seconds) /// @param timeout_sec specifies integral part of the timeout (in seconds)
/// @param timeout_usec specifies fractional part of the timeout /// @param timeout_usec specifies fractional part of the timeout
/// (in microseconds) /// (in microseconds)
/// ///
/// @throw isc::BadValue if timeout_usec is greater than one million /// @return Pkt4 object representing received packet (or NULL)
/// @throw isc::dhcp::SocketReadError if error occurred when receiving a
/// packet.
/// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
/// interrupted by a signal.
///
/// @return Pkt6 object representing received packet (or NULL)
Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0); Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0);
Pkt6Ptr receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec = 0); /// @brief Receive IPv4 packets or data from external sockets
Pkt6Ptr receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec = 0);
/// @brief Tries to receive IPv4 packet over open IPv4 sockets.
/// ///
/// Attempts to receive a single DHCPv4 message over any of the open /// Wrapper around calls to either @c receive4Direct or @c
/// IPv4 sockets. If reception is successful and all information about /// receive4Indirect. The former is called when packet queuing is
/// its sender is obtained, Pkt4 object is created and returned. /// disabled, the latter when it is enabled.
///
/// This method also checks if data arrived over registered external socket.
/// This data may be of a different protocol family than AF_INET.
/// ///
/// @param timeout_sec specifies integral part of the timeout (in seconds) /// @param timeout_sec specifies integral part of the timeout (in seconds)
/// @param timeout_usec specifies fractional part of the timeout /// @param timeout_usec specifies fractional part of the timeout
/// (in microseconds) /// (in microseconds)
/// ///
/// @throw isc::BadValue if timeout_usec is greater than one million
/// @throw isc::dhcp::SocketReadError if error occurred when receiving a
/// packet.
/// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
/// interrupted by a signal.
///
/// @return Pkt4 object representing received packet (or NULL) /// @return Pkt4 object representing received packet (or NULL)
Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0); Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0);
Pkt4Ptr receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec = 0);
Pkt4Ptr receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec = 0);
/// Opens UDP/IP socket and binds it to address, interface and port. /// Opens UDP/IP socket and binds it to address, interface and port.
/// ///
/// Specific type of socket (UDP/IPv4 or UDP/IPv6) depends on passed addr /// Specific type of socket (UDP/IPv4 or UDP/IPv6) depends on passed addr
...@@ -1125,6 +1101,50 @@ protected: ...@@ -1125,6 +1101,50 @@ protected:
const uint16_t port, const bool receive_bcast = false, const uint16_t port, const bool receive_bcast = false,
const bool send_bcast = false); const bool send_bcast = false);
/// @brief Receive IPv4 packets directly or data from external sockets.
///
/// Attempts to receive a single DHCPv4 message over any of the open
/// IPv4 sockets. If reception is successful and all information about
/// its sender is obtained, an Pkt4 object is created and returned.
///
/// This method also checks if data arrived over registered external socket.
/// This data may be of a different protocol family than AF_INET.
///
/// @param timeout_sec specifies integral part of the timeout (in seconds)
/// @param timeout_usec specifies fractional part of the timeout
/// (in microseconds)
///
/// @throw isc::BadValue if timeout_usec is greater than one million
/// @throw isc::dhcp::SocketReadError if error occurred when receiving a
/// packet.
/// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
/// interrupted by a signal.
///
/// @return Pkt4 object representing received packet (or NULL)
Pkt4Ptr receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec = 0);
/// @brief Receive IPv4 packets indirectly or data from external sockets.
///
/// Attempts to receive a single DHCPv4 message from the packet queue.
/// The queue is populated by the receiver thread. If a packet is waiting
/// in the queue, a Pkt4 returned.
///
/// This method also checks if data arrived over registered external socket.
/// This data may be of a different protocol family than AF_INET.
///
/// @param timeout_sec specifies integral part of the timeout (in seconds)
/// @param timeout_usec specifies fractional part of the timeout
/// (in microseconds)
///
/// @throw isc::BadValue if timeout_usec is greater than one million
/// @throw isc::dhcp::SocketReadError if error occurred when receiving a
/// packet.
/// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
/// interrupted by a signal.
///
/// @return Pkt4 object representing received packet (or NULL)
Pkt4Ptr receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec = 0);
/// @brief Opens IPv6 socket. /// @brief Opens IPv6 socket.
/// ///
/// Please do not use this method directly. Use openSocket instead. /// Please do not use this method directly. Use openSocket instead.
...@@ -1142,6 +1162,51 @@ protected: ...@@ -1142,6 +1162,51 @@ protected:
int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr, int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr,
uint16_t port, const bool join_multicast); uint16_t port, const bool join_multicast);
/// @brief Receive IPv6 packets directly or data from external sockets.
///
/// Attempts to receive a single DHCPv6 message over any of the open
/// IPv6 sockets. If reception is successful and all information about
/// its sender is obtained, an Pkt6 object is created and returned.
///
/// This method also checks if data arrived over registered external socket.
/// This data may be of a different protocol family than AF_INET.
///
/// @param timeout_sec specifies integral part of the timeout (in seconds)
/// @param timeout_usec specifies fractional part of the timeout
/// (in microseconds)
///
/// @throw isc::BadValue if timeout_usec is greater than one million
/// @throw isc::dhcp::SocketReadError if error occurred when receiving a
/// packet.
/// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
/// interrupted by a signal.
///
/// @return Pkt6 object representing received packet (or NULL)
Pkt6Ptr receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec = 0);
/// @brief Receive IPv6 packets indirectly or data from external sockets.
///
/// Attempts to receive a single DHCPv6 message from the packet queue.
/// The queue is populated by the receiver thread. If a packet is waiting
/// in the queue, a Pkt6 returned.
///
/// This method also checks if data arrived over registered external socket.
/// This data may be of a different protocol family than AF_INET.
///
/// @param timeout_sec specifies integral part of the timeout (in seconds)
/// @param timeout_usec specifies fractional part of the timeout
/// (in microseconds)
///
/// @throw isc::BadValue if timeout_usec is greater than one million
/// @throw isc::dhcp::SocketReadError if error occurred when receiving a
/// packet.
/// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
/// interrupted by a signal.
///
/// @return Pkt6 object representing received packet (or NULL)
Pkt6Ptr receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec = 0);
/// @brief Stub implementation of network interface detection. /// @brief Stub implementation of network interface detection.
/// ///
/// This implementations reads a single line from interfaces.txt file /// This implementations reads a single line from interfaces.txt file
......
...@@ -449,7 +449,7 @@ public: ...@@ -449,7 +449,7 @@ public:
/// @brief Tests the ability to send and receive DHCPv6 packets /// @brief Tests the ability to send and receive DHCPv6 packets
/// ///
/// This test calls @r IfaceMgr::configureDHCPqueue, passing int the /// This test calls @r IfaceMgr::configureDHCPPacketQueue, passing in the
/// given queue configuration. It then calls IfaceMgr::startDHCPReceiver /// given queue configuration. It then calls IfaceMgr::startDHCPReceiver
/// and verifies whether or not the receive thread has been started as /// and verifies whether or not the receive thread has been started as
/// expected. Next it creates a generic DHCPv6 packet and sends it over /// expected. Next it creates a generic DHCPv6 packet and sends it over
...@@ -465,11 +465,11 @@ public: ...@@ -465,11 +465,11 @@ public:
// Testing socket operation in a portable way is tricky // Testing socket operation in a portable way is tricky
// without interface detection implemented // without interface detection implemented
// let's assume that every supported OS have lo interface // let's assume that every supported OS have lo interface
IOAddress loAddr("::1"); IOAddress lo_addr("::1");
int socket1 = 0, socket2 = 0; int socket1 = 0, socket2 = 0;
EXPECT_NO_THROW( EXPECT_NO_THROW(
socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547); socket1 = ifacemgr->openSocket(LOOPBACK, lo_addr, 10547);
socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546); socket2 = ifacemgr->openSocket(LOOPBACK, lo_addr, 10546);
); );
EXPECT_GE(socket1, 0); EXPECT_GE(socket1, 0);
...@@ -537,7 +537,7 @@ public: ...@@ -537,7 +537,7 @@ public:
/// @brief Tests the ability to send and receive DHCPv4 packets /// @brief Tests the ability to send and receive DHCPv4 packets
/// ///
/// This test calls @r IfaceMgr::configureDHCPqueue, passing int the /// This test calls @r IfaceMgr::configureDHCPPacketQueue, passing in the
/// given queue configuration. It then calls IfaceMgr::startDHCPReceiver /// given queue configuration. It then calls IfaceMgr::startDHCPReceiver
/// and verifies whether or not the receive thread has been started as /// and verifies whether or not the receive thread has been started as
/// expected. Next it creates a DISCOVER packet and sends it over /// expected. Next it creates a DISCOVER packet and sends it over
...@@ -553,10 +553,10 @@ public: ...@@ -553,10 +553,10 @@ public:
// Testing socket operation in a portable way is tricky // Testing socket operation in a portable way is tricky
// without interface detection implemented. // without interface detection implemented.
// Let's assume that every supported OS has lo interface // Let's assume that every supported OS has lo interface
IOAddress loAddr("127.0.0.1"); IOAddress lo_addr("127.0.0.1");
int socket1 = 0; int socket1 = 0;
EXPECT_NO_THROW( EXPECT_NO_THROW(
socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000); socket1 = ifacemgr->openSocket(LOOPBACK, lo_addr, DHCP4_SERVER_PORT + 10000);
); );