libkea_dhcp___la_SOURCES += option_string.cc option_string.h
libkea_dhcp___la_SOURCES += option_vendor.cc option_vendor.h
libkea_dhcp___la_SOURCES += option_vendor_class.cc option_vendor_class.h
-libkea_dhcp___la_SOURCES += packet_queue.h
-libkea_dhcp___la_SOURCES += packet_queue_mgr.h
-libkea_dhcp___la_SOURCES += packet_queue_mgr4.cc packet_queue_mgr4.h
-libkea_dhcp___la_SOURCES += packet_queue_mgr6.cc packet_queue_mgr6.h
+libkea_dhcp___la_SOURCES += packet_queue.h
+libkea_dhcp___la_SOURCES += packet_queue_ring.h
+libkea_dhcp___la_SOURCES += packet_queue_mgr.h
+libkea_dhcp___la_SOURCES += packet_queue_mgr4.cc packet_queue_mgr4.h
+libkea_dhcp___la_SOURCES += packet_queue_mgr6.cc packet_queue_mgr6.h
libkea_dhcp___la_SOURCES += pkt.cc pkt.h
libkea_dhcp___la_SOURCES += pkt4.cc pkt4.h
libkea_dhcp___la_SOURCES += pkt4o6.cc pkt4o6.h
libkea_dhcp___la_SOURCES += pkt_filter6.h pkt_filter6.cc
libkea_dhcp___la_SOURCES += pkt_filter_inet.cc pkt_filter_inet.h
libkea_dhcp___la_SOURCES += pkt_filter_inet6.cc pkt_filter_inet6.h
-libkea_dhcp___la_SOURCES += socket_info.h
+libkea_dhcp___la_SOURCES += socket_info.h
# Utilize Linux Packet Filtering on Linux.
if OS_LINUX
option_vendor.h \
option_vendor_class.h \
packet_queue.h \
+ packet_queue_ring.h \
packet_queue_mgr.h \
packet_queue_mgr4.h \
packet_queue_mgr6.h \
continue;
}
- // Let's find out which interface/socket has data.
+ // Iterate over interface sockets and read a packet from each ready socket
+ Pkt4PtrSocketInfoList pkt_list;
+ Pkt4Ptr pkt;
BOOST_FOREACH(iface, ifaces_) {
BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
if (FD_ISSET(s.sockfd_, &sockets)) {
- receiveDHCP4Packet(*iface, s);
- // Can take time so check one more time the watch socket.
- if (dhcp_receiver_->shouldTerminate()) {
- return;
+ pkt = receiveDHCP4Packet(*iface, s);
+ if (pkt) {
+ pkt_list.push_back(Pkt4PtrSocketInfoPair(pkt, s));
}
}
}
}
+
+ // If we read any packets push them onto the queue
+ if (pkt_list.size()) {
+ getPacketQueue4()->enqueuePackets(pkt_list);
+ dhcp_receiver_->markReady(WatchedThread::READY);
+ }
}
}
continue;
}
- // Let's find out which interface/socket has data.
+ // Iterate over interface sockets and read a packet from each ready socket
+ Pkt6PtrSocketInfoList pkt_list;
+ Pkt6Ptr pkt;
BOOST_FOREACH(iface, ifaces_) {
BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
if (FD_ISSET(s.sockfd_, &sockets)) {
- receiveDHCP6Packet(s);
- // Can take time so check one more time the watch socket.
- if (dhcp_receiver_->shouldTerminate()) {
- return;
+ pkt = receiveDHCP6Packet(s);
+ if (pkt) {
+ pkt_list.push_back(Pkt6PtrSocketInfoPair(pkt, s));
}
}
}
}
+
+ // If we read any packets push them onto the queue
+ if (pkt_list.size()) {
+ getPacketQueue6()->enqueuePackets(pkt_list);
+ dhcp_receiver_->markReady(WatchedThread::READY);
+ }
}
}
-void
+Pkt4Ptr
IfaceMgr::receiveDHCP4Packet(Iface& iface, const SocketInfo& socket_info) {
int len;
+ Pkt4Ptr pkt;
int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
if (result < 0) {
// Signal the error to receive4.
dhcp_receiver_->setError(strerror(errno));
- return;
+ return (pkt);
}
+
if (len == 0) {
// Nothing to read.
- return;
+ return (pkt);
}
- Pkt4Ptr pkt;
-
try {
pkt = packet_filter_->receive(iface, socket_info);
} catch (const std::exception& ex) {
dhcp_receiver_->setError("packet filter receive() failed");
}
- if (pkt) {
- getPacketQueue4()->enqueuePacket(pkt, socket_info);
- dhcp_receiver_->markReady(WatchedThread::READY);
- }
+ return(pkt);
}
-void
+Pkt6Ptr
IfaceMgr::receiveDHCP6Packet(const SocketInfo& socket_info) {
+ Pkt6Ptr pkt;
int len;
int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
if (result < 0) {
// Signal the error to receive6.
dhcp_receiver_->setError(strerror(errno));
- return;
+ return (pkt);
}
if (len == 0) {
// Nothing to read.
- return;
+ return (pkt);
}
- Pkt6Ptr pkt;
-
try {
pkt = packet_filter6_->receive(socket_info);
} catch (const std::exception& ex) {
dhcp_receiver_->setError("packet filter receive() failed");
}
- if (pkt) {
- getPacketQueue6()->enqueuePacket(pkt, socket_info);
- dhcp_receiver_->markReady(WatchedThread::READY);
- }
+ return(pkt);
}
uint16_t
/// watch socket, and exits if it is marked ready. This is method
/// is used as the worker function in the thread created by @c
/// startDHCP4Receiver(). It currently uses select() to monitor
- /// socket readiness. If the select errors out (other than EINTR),
- /// it marks the "error" watch socket as ready.
+ /// socket readiness. When any interface socket is ready, it
+ /// iterates over all of the interface sockets reading one packet
+ /// per ready socket into a list. It then passes that list to
+ /// queue, and sets the "ready" watch socket. If the select
+ /// errors out (other than EINTR), it marks the "error" watch socket
+ /// as ready.
void receiveDHCP4Packets();
/// @brief Receives a single DHCPv4 packet from an interface socket
///
/// Called by @c receiveDHPC4Packets when a socket fd is flagged as
/// ready. It uses the DHCPv4 packet filter to receive a single packet
- /// from the given interface socket, adds it to the packet queue, and
- /// marks the "receive" watch socket ready. If an error occurs during
- /// the read, the "error" watch socket is marked ready.
+ /// from the given interface socket and returns it. If an error occurs
+ /// during the read, the "error" watch socket is marked ready.
///
/// @param iface interface
/// @param socket_info structure holding socket information
- void receiveDHCP4Packet(Iface& iface, const SocketInfo& socket_info);
+ /// @return A pointer to the packet read, or an empty pointer
+ Pkt4Ptr receiveDHCP4Packet(Iface& iface, const SocketInfo& socket_info);
/// @brief DHCPv6 receiver method.
///
/// watch socket, and exits if it is marked ready. This is method
/// is used as the worker function in the thread created by @c
/// startDHCP6Receiver(). It currently uses select() to monitor
- /// socket readiness. If the select errors out (other than EINTR),
- /// it marks the "error" watch socket as ready.
+ /// socket readiness. When any interface socket is ready, it
+ /// iterates over all of the interface sockets reading one packet
+ /// per ready socket into a list. It then passes that list to
+ /// queue, and sets the "ready" watch socket. If the select
+ /// errors out (other than EINTR), it marks the "error" watch socket
+ /// as ready.
void receiveDHCP6Packets();
/// @brief Receives a single DHCPv6 packet from an interface socket
///
/// Called by @c receiveDHPC6Packets when a socket fd is flagged as
/// ready. It uses the DHCPv6 packet filter to receive a single packet
- /// from the given interface socket, adds it to the packet queue, and
- /// marks the "receive" watch socket ready. If an error occurs during
- /// the read, the "error" watch socket is marked ready.
+ /// from the given interface socket and returns it. If an error occurs
+ /// during the read, the "error" watch socket is marked ready.
///
/// @param socket_info structure holding socket information
- void receiveDHCP6Packet(const SocketInfo& socket_info);
+ /// @return A pointer to the packet read, or an empty pointer
+ Pkt6Ptr receiveDHCP6Packet(const SocketInfo& socket_info);
/// Holds instance of a class derived from PktFilter, used by the
/// IfaceMgr to open sockets and send/receive packets through these
#include <dhcp/socket_info.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
-#include <util/threads/sync.h>
-#include <boost/function.hpp>
-#include <boost/circular_buffer.hpp>
#include <sstream>
namespace isc {
/// Virtual destructor
virtual ~PacketQueue(){};
+ /// @brief Pairs a packet pointer with its source socket.
+ typedef std::pair<PacketTypePtr, SocketInfo> PacketPtrTypeSocketInfoPair;
+ /// @brief Defines a list of packets and their sockets
+ typedef std::vector<PacketPtrTypeSocketInfoPair> PacketPtrTypeSocketInfoList;
+
/// @brief Adds a packet to the queue
///
- /// Calls @c shouldDropPacket to determine if the packet should be queued
- /// or dropped. If it should be queued it is added to the end of the
- /// queue specified by the "to" parameter.
- ///
- /// @param packet packet to enqueue
- /// @param source socket the packet came from
- /// @param to end of the queue from which to remove packet(s).
- /// Defaults to BACK.
+ /// Adds the list of packets to the queue. The list contains pairs of
+ /// packets and their originating socket info structs. Derivations determine
+ /// which packets to queue and how to queue them.
///
- void enqueuePacket(PacketTypePtr packet, const SocketInfo& source,
- const QueueEnd& to=QueueEnd::BACK) {
- if (!shouldDropPacket(packet, source)) {
- pushPacket(packet, to);
- }
- }
+ /// @param packets list of packets to queue
+ virtual void enqueuePackets(const PacketPtrTypeSocketInfoList& /*packets*/) = 0;
/// @brief Dequeues the next packet from the queue
///
- /// Calls @eatPackets to discard packets as needed, and then
- /// dequeues the next packet (if any) and returns it. Packets
- /// are dequeued from the end of the queue specified by the "from"
- /// parameter.
- ///
- /// @param from end of the queue from which to remove packet(s).
- /// Defaults to FRONT.
+ /// Dequeues the next packet (if any) and returns it. Derivations determine
+ /// how packets are dequeued.
///
/// @return A pointer to dequeued packet, or an empty pointer
/// if the queue is empty.
- PacketTypePtr dequeuePacket(const QueueEnd& from=QueueEnd::FRONT) {
- eatPackets(from);
- return(popPacket(from));
- }
-
- /// @brief Determines if a packet should be discarded.
- ///
- /// This function is called at the beginning of @c enqueuePacket and
- /// provides an opportunity to examine the packet and its source
- /// and decide whether it should be dropped or added to the queue.
- /// Derivations are expected to provide implementations based on
- /// their own requirements. Bear in mind that the packet has NOT
- /// been unpacked at this point. The default implementation simply
- /// returns false.
- ///
- /// @param packet the packet under consideration
- /// @param source the socket the packet came from
- ///
- /// @return true if the packet should be dropped, false if it should be
- /// kept.
- virtual bool shouldDropPacket(PacketTypePtr /* packet */,
- const SocketInfo& /* source */) {
- return (false);
- }
-
- /// @brief Discards packets from one end of the queue.
- ///
- /// This function is called at the beginning of @c dequeuePacket and
- /// provides an opportunity to examine and discard packets from
- /// the queue prior to dequeuing the next packet to be
- /// processed. Derivations are expected to provide implementations
- /// based on their own requirements. The default implemenation is to
- /// to simply return without skipping any packets.
- ///
- /// @param from end of the queue from which packets should discarded
- /// This is passed in from @c dequeuePackets.
- ///
- /// @param from specifies the end of the queue from which packets
- /// should be discarded.
- ///
- /// @return The number of packets discarded.
- virtual int eatPackets(const QueueEnd& /* from */) {
- return (0);
- }
-
- /// @brief Pushes a packet onto the queue
- ///
- /// Adds a packet onto the end of queue specified.
- ///
- /// @param packet packet to add to the queue
- /// @param to specifies the end of the queue to which the packet
- /// should be added.
- virtual void pushPacket(PacketTypePtr& packet, const QueueEnd& to=QueueEnd::BACK) = 0;
-
- /// @brief Pops a packet from the queue
- ///
- /// Removes a packet from the end of the queue specified and returns it.
- ///
- /// @param from specifies the end of the queue from which the packet
- /// should be taken.
- ///
- /// @return A pointer to dequeued packet, or an empty pointer
- /// if the queue is empty.
- virtual PacketTypePtr popPacket(const QueueEnd& from=QueueEnd::FRONT) = 0;
-
- /// @brief Gets the packet currently at one end of the queue
- ///
- /// Returns a pointer the packet at the specified end of the
- /// queue without dequeuing it.
- ///
- /// @param from specifies which end of the queue to examine.
- ///
- /// @return A pointer to packet, or an empty pointer if the
- /// queue is empty.
- virtual const PacketTypePtr peek(const QueueEnd& from=QueueEnd::FRONT) const = 0;
+ virtual PacketTypePtr dequeuePacket() = 0;
/// @brief return True if the queue is empty.
virtual bool empty() const = 0;
- /// @todo size may not apply either... what if there are two internal buffers?
/// @brief Returns the current number of packets in the buffer.
virtual size_t getSize() const = 0;
}
/// @return Fetches the logical name of the type of this queue.
- std::string getQueueType() {
+ std::string getQueueType() const {
return (queue_type_);
};
};
+
/// @brief Defines pointer to the DHCPv4 queue interface used at the application level.
/// This is the type understood by IfaceMgr and the type that should be returned by
/// DHCPv4 packet queue factories.
typedef boost::shared_ptr<PacketQueue<Pkt4Ptr>> PacketQueue4Ptr;
+/// @brief Defines DHCPv4 packet pointer/socket info pair
+typedef std::pair<Pkt4Ptr, SocketInfo> Pkt4PtrSocketInfoPair;
+/// @brief Defines DHCPv4 packet pointer/socket info pair list
+typedef std::vector<Pkt4PtrSocketInfoPair> Pkt4PtrSocketInfoList;
/// @brief Defines pointer to the DHCPv6 queue interface used at the application level.
/// This is the type understood by IfaceMgr and the type that should be returned by
/// DHCPv6 packet queue factories.
typedef boost::shared_ptr<PacketQueue<Pkt6Ptr>> PacketQueue6Ptr;
-
-
-/// @brief Provides an abstract ring-buffer implementation of the PacketQueue interface.
-template<typename PacketTypePtr>
-class PacketQueueRing : public PacketQueue<PacketTypePtr> {
-public:
- /// @brief Minimum queue capacity permitted. Below five is pretty much
- /// nonsensical.
- static const size_t MIN_RING_CAPACITY = 5;
-
- /// @brief Constructor
- ///
- /// @param queue_type logical name of the queue implementation
- /// @param capacity maximum number of packets the queue can hold
- PacketQueueRing(const std::string& queue_type, size_t capacity)
- : PacketQueue<PacketTypePtr>(queue_type) {
- queue_.set_capacity(capacity);
- }
-
- /// @brief virtual Destructor
- virtual ~PacketQueueRing(){};
-
- /// @brief Pushes a packet onto the queue
- ///
- /// Adds a packet onto the end of queue specified. Note that this
- /// function is protected by a Mutex.
- ///
- /// @param packet packet to add to the queue
- /// @param to specifies the end of the queue to which the packet
- /// should be added.
- virtual void pushPacket(PacketTypePtr& packet, const QueueEnd& to=QueueEnd::BACK) {
- isc::util::thread::Mutex::Locker lock(mutex_);
- if (to == QueueEnd::BACK) {
- queue_.push_back(packet);
- } else {
- queue_.push_front(packet);
- }
- }
-
- /// @brief Pops a packet from the queue
- ///
- /// Removes a packet from the end of the queue specified and returns it. Note
- /// that this function is protected by a Mutex.
- ///
- /// @param from specifies the end of the queue from which the packet
- /// should be taken.
- ///
- /// @return A pointer to dequeued packet, or an empty pointer
- /// if the queue is empty.
- virtual PacketTypePtr popPacket(const QueueEnd& from = QueueEnd::FRONT) {
- isc::util::thread::Mutex::Locker lock(mutex_);
- PacketTypePtr packet;
- if (queue_.empty()) {
- return (packet);
- }
-
- if (from == QueueEnd::FRONT) {
- packet = queue_.front();
- queue_.pop_front();
- } else {
- packet = queue_.back();
- queue_.pop_back();
- }
-
- return (packet);
- }
-
-
- /// @brief Gets the packet currently at one end of the queue
- ///
- /// Returns a pointer the packet at the specified end of the
- /// queue without dequeuing it.
- ///
- /// @param from specifies which end of the queue to examine.
- ///
- /// @return A pointer to packet, or an empty pointer if the
- /// queue is empty.
- virtual const PacketTypePtr peek(const QueueEnd& from=QueueEnd::FRONT) const {
- PacketTypePtr packet;
- if (!queue_.empty()) {
- packet = (from == QueueEnd::FRONT ? queue_.front() : queue_.back());
- }
-
- return (packet);
- }
-
- /// @brief Returns True if the queue is empty.
- virtual bool empty() const {
- return(queue_.empty());
- }
-
- /// @brief Returns the maximum number of packets allowed in the buffer.
- virtual size_t getCapacity() const {
- return (queue_.capacity());
- }
-
- /// @brief Sets the maximum number of packets allowed in the buffer.
- ///
- /// @todo - do we want to change size on the fly? This might need
- /// to be private, called only by constructor
- ///
- /// @throw BadValue if capacity is too low.
- virtual void setCapacity(size_t capacity) {
- if (capacity < MIN_RING_CAPACITY) {
- isc_throw(BadValue, "Queue capacity of " << capacity
- << " is invalid. It must be at least "
- << MIN_RING_CAPACITY);
- }
-
- /// @todo should probably throw if it's zero
- queue_.set_capacity(capacity);
- }
-
- /// @brief Returns the current number of packets in the buffer.
- virtual size_t getSize() const {
- return (queue_.size());
- }
-
- /// @brief Discards all packets currently in the buffer.
- virtual void clear() {
- queue_.clear();
- }
-
- /// @brief Fetches pertinent information
- virtual data::ElementPtr getInfo() const {
- data::ElementPtr info = PacketQueue<PacketTypePtr>::getInfo();
- info->set("capacity", data::Element::create(static_cast<int64_t>(getCapacity())));
- info->set("size", data::Element::create(static_cast<int64_t>(getSize())));
- return(info);
- }
-
-private:
-
- /// @brief Packet queue
- boost::circular_buffer<PacketTypePtr> queue_;
-
- /// @brief Mutex for protecting queue accesses.
- isc::util::thread::Mutex mutex_;
-};
-
-
-/// @brief DHCPv4 packet queue buffer implementation
-///
-/// This implementation does not (currently) add any drop
-/// or packet skip logic, it operates as a verbatim ring
-/// queue for DHCPv4 packets.
-///
-class PacketQueueRing4 : public PacketQueueRing<Pkt4Ptr> {
-public:
- /// @brief Constructor
- ///
- /// @param queue_type logical name of the queue implementation
- /// @param capacity maximum number of packets the queue can hold
- PacketQueueRing4(const std::string& queue_type, size_t capacity)
- : PacketQueueRing(queue_type, capacity) {
- };
-
- /// @brief virtual Destructor
- virtual ~PacketQueueRing4(){}
-};
-
-/// @brief DHCPv6 packet queue buffer implementation
-///
-/// This implementation does not (currently) add any drop
-/// or packet skip logic, it operates as a verbatim ring
-/// queue for DHCPv6 packets.
-///
-class PacketQueueRing6 : public PacketQueueRing<Pkt6Ptr> {
-public:
- /// @brief Constructor
- ///
- /// @param queue_type logical name of the queue implementation
- /// @param capacity maximum number of packets the queue can hold
- PacketQueueRing6(const std::string& queue_type, size_t capacity)
- : PacketQueueRing(queue_type, capacity) {
- };
-
- /// @brief virtual Destructor
- virtual ~PacketQueueRing6(){}
-};
-
+/// @brief Defines DHCPv6 packet pointer/socket info pair
+typedef std::pair<Pkt6Ptr, SocketInfo> Pkt6PtrSocketInfoPair;
+/// @brief Defines DHCPv6 packet pointer/socket info pair list
+typedef std::vector<Pkt6PtrSocketInfoPair> Pkt6PtrSocketInfoList;
}; // namespace isc::dhcp
}; // namespace isc
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
+#include <dhcp/packet_queue_ring.h>
#include <dhcp/packet_queue_mgr4.h>
#include <boost/scoped_ptr.hpp>
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
+#include <dhcp/packet_queue_ring.h>
#include <dhcp/packet_queue_mgr6.h>
#include <boost/scoped_ptr.hpp>
--- /dev/null
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef PACKET_QUEUE_RING_H
+#define PACKET_QUEUE_RING_H
+
+#include <dhcp/packet_queue.h>
+#include <util/threads/sync.h>
+
+#include <boost/function.hpp>
+#include <boost/circular_buffer.hpp>
+#include <sstream>
+
+namespace isc {
+
+namespace dhcp {
+
+/// @brief Provides an abstract ring-buffer implementation of the PacketQueue interface.
+template<typename PacketTypePtr>
+class PacketQueueRing : public PacketQueue<PacketTypePtr> {
+public:
+ /// @brief Minimum queue capacity permitted. Below five is pretty much
+ /// nonsensical.
+ static const size_t MIN_RING_CAPACITY = 5;
+
+ /// @brief Constructor
+ ///
+ /// @param queue_type logical name of the queue implementation
+ /// @param capacity maximum number of packets the queue can hold
+ PacketQueueRing(const std::string& queue_type, size_t capacity)
+ : PacketQueue<PacketTypePtr>(queue_type) {
+ queue_.set_capacity(capacity);
+ }
+
+ /// @brief virtual Destructor
+ virtual ~PacketQueueRing(){};
+
+ /// @brief Adds a packet to the queue
+ ///
+ /// Iterates over the packet list, passing the packet and its socket info
+ /// into @c shouldDropPacket to determine whether or not the packet should
+ /// added to the queue. Note this method locks the queue's mutex upon entry.
+ ///
+ /// @param packets list of packets to queue
+ virtual void enqueuePackets(const typename
+ PacketQueue<PacketTypePtr>::PacketPtrTypeSocketInfoList& packets) {
+ isc::util::thread::Mutex::Locker lock(mutex_);
+ for (auto pspair : packets) {
+ if (!shouldDropPacket(pspair.first, pspair.second)) {
+ pushPacket(pspair.first);
+ }
+ }
+ }
+
+ /// @brief Dequeues the next packet from the queue
+ ///
+ /// Dequeues the next packet (if any) and returns it. Note this method
+ /// locks the queue'sm mutex upon entry.
+ ///
+ /// @return A pointer to dequeued packet, or an empty pointer
+ /// if the queue is empty.
+ virtual PacketTypePtr dequeuePacket() {
+ isc::util::thread::Mutex::Locker lock(mutex_);
+ eatPackets(QueueEnd::FRONT);
+ return(popPacket());
+ }
+
+ /// @brief Determines if a packet should be discarded.
+ ///
+ /// This function is called in @c enqueuePackets for each packet
+ /// in its packet list. It provides an opportunity to examine the
+ /// packet and its source and decide whether it should be dropped
+ /// or added to the queue. Derivations are expected to provide
+ /// implementations based on their own requirements. Bear in mind
+ /// that the packet has NOT been unpacked at this point. The default
+ /// implementation simply returns false (i.e. keep the packet).
+ ///
+ /// @param packet the packet under consideration
+ /// @param source the socket the packet came from
+ ///
+ /// @return true if the packet should be dropped, false if it should be
+ /// kept.
+ virtual bool shouldDropPacket(PacketTypePtr /* packet */,
+ const SocketInfo& /* source */) {
+ return (false);
+ }
+
+ /// @brief Discards packets from one end of the queue.
+ ///
+ /// This function is called at the beginning of @c dequeuePacket and
+ /// provides an opportunity to examine and discard packets from
+ /// the queue prior to dequeuing the next packet to be
+ /// processed. Derivations are expected to provide implementations
+ /// based on their own requirements. The default implemenation is to
+ /// to simply return without skipping any packets.
+ ///
+ /// @param from end of the queue from which packets should discarded
+ /// This is passed in from @c dequeuePackets.
+ ///
+ /// @param from specifies the end of the queue from which packets
+ /// should be discarded.
+ ///
+ /// @return The number of packets discarded.
+ virtual int eatPackets(const QueueEnd& /* from */) {
+ return (0);
+ }
+
+ /// @brief Pushes a packet onto the queue
+ ///
+ /// Adds a packet onto the end of queue specified.
+ ///
+ /// @param packet packet to add to the queue
+ /// @param to specifies the end of the queue to which the packet
+ /// should be added.
+ virtual void pushPacket(PacketTypePtr& packet, const QueueEnd& to=QueueEnd::BACK) {
+ if (to == QueueEnd::BACK) {
+ queue_.push_back(packet);
+ } else {
+ queue_.push_front(packet);
+ }
+ }
+
+ /// @brief Pops a packet from the queue
+ ///
+ /// Removes a packet from the end of the queue specified and returns it.
+ ///
+ /// @param from specifies the end of the queue from which the packet
+ /// should be taken.
+ ///
+ /// @return A pointer to dequeued packet, or an empty pointer
+ /// if the queue is empty.
+ virtual PacketTypePtr popPacket(const QueueEnd& from = QueueEnd::FRONT) {
+ PacketTypePtr packet;
+ if (queue_.empty()) {
+ return (packet);
+ }
+
+ if (from == QueueEnd::FRONT) {
+ packet = queue_.front();
+ queue_.pop_front();
+ } else {
+ packet = queue_.back();
+ queue_.pop_back();
+ }
+
+ return (packet);
+ }
+
+
+ /// @brief Gets the packet currently at one end of the queue
+ ///
+ /// Returns a pointer the packet at the specified end of the
+ /// queue without dequeuing it.
+ ///
+ /// @param from specifies which end of the queue to examine.
+ ///
+ /// @return A pointer to packet, or an empty pointer if the
+ /// queue is empty.
+ virtual const PacketTypePtr peek(const QueueEnd& from=QueueEnd::FRONT) const {
+ PacketTypePtr packet;
+ if (!queue_.empty()) {
+ packet = (from == QueueEnd::FRONT ? queue_.front() : queue_.back());
+ }
+
+ return (packet);
+ }
+
+ /// @brief Returns True if the queue is empty.
+ virtual bool empty() const {
+ return(queue_.empty());
+ }
+
+ /// @brief Returns the maximum number of packets allowed in the buffer.
+ virtual size_t getCapacity() const {
+ return (queue_.capacity());
+ }
+
+ /// @brief Sets the maximum number of packets allowed in the buffer.
+ ///
+ /// @todo - do we want to change size on the fly? This might need
+ /// to be private, called only by constructor
+ ///
+ /// @throw BadValue if capacity is too low.
+ virtual void setCapacity(size_t capacity) {
+ if (capacity < MIN_RING_CAPACITY) {
+ isc_throw(BadValue, "Queue capacity of " << capacity
+ << " is invalid. It must be at least "
+ << MIN_RING_CAPACITY);
+ }
+
+ /// @todo should probably throw if it's zero
+ queue_.set_capacity(capacity);
+ }
+
+ /// @brief Returns the current number of packets in the buffer.
+ virtual size_t getSize() const {
+ return (queue_.size());
+ }
+
+ /// @brief Discards all packets currently in the buffer.
+ virtual void clear() {
+ queue_.clear();
+ }
+
+ /// @brief Fetches pertinent information
+ virtual data::ElementPtr getInfo() const {
+ data::ElementPtr info = PacketQueue<PacketTypePtr>::getInfo();
+ info->set("capacity", data::Element::create(static_cast<int64_t>(getCapacity())));
+ info->set("size", data::Element::create(static_cast<int64_t>(getSize())));
+ return(info);
+ }
+
+private:
+
+ /// @brief Packet queue
+ boost::circular_buffer<PacketTypePtr> queue_;
+
+ /// @brief Mutex for protecting queue accesses.
+ isc::util::thread::Mutex mutex_;
+};
+
+
+/// @brief DHCPv4 packet queue buffer implementation
+///
+/// This implementation does not (currently) add any drop
+/// or packet skip logic, it operates as a verbatim ring
+/// queue for DHCPv4 packets.
+///
+class PacketQueueRing4 : public PacketQueueRing<Pkt4Ptr> {
+public:
+ /// @brief Constructor
+ ///
+ /// @param queue_type logical name of the queue implementation
+ /// @param capacity maximum number of packets the queue can hold
+ PacketQueueRing4(const std::string& queue_type, size_t capacity)
+ : PacketQueueRing(queue_type, capacity) {
+ };
+
+ /// @brief virtual Destructor
+ virtual ~PacketQueueRing4(){}
+};
+
+/// @brief DHCPv6 packet queue buffer implementation
+///
+/// This implementation does not (currently) add any drop
+/// or packet skip logic, it operates as a verbatim ring
+/// queue for DHCPv6 packets.
+///
+class PacketQueueRing6 : public PacketQueueRing<Pkt6Ptr> {
+public:
+ /// @brief Constructor
+ ///
+ /// @param queue_type logical name of the queue implementation
+ /// @param capacity maximum number of packets the queue can hold
+ PacketQueueRing6(const std::string& queue_type, size_t capacity)
+ : PacketQueueRing(queue_type, capacity) {
+ };
+
+ /// @brief virtual Destructor
+ virtual ~PacketQueueRing6(){}
+};
+
+}; // namespace isc::dhcp
+}; // namespace isc
+
+#endif // PACKET_QUEUE_RING_H
// OK, Send the PACKET!
EXPECT_NO_THROW(ifacemgr->send(sendPkt));
+ (ifacemgr->send(sendPkt));
// Now let's try and receive it.
boost::shared_ptr<Pkt4> rcvPkt;
// Given an empty pointer, queueing should be disabled.
// This should do direct reception.
- sendReceive4Test(queue_control, false);
+ {
+ SCOPED_TRACE("no queue control");
+ sendReceive4Test(queue_control, false);
+ }
- // Now let's populate queue control.
- queue_control = makeQueueConfig(PacketQueueMgr4::DEFAULT_QUEUE_TYPE4, 500, false);
- // With queueing disabled, we should use direct reception.
- sendReceive4Test(queue_control, false);
+ {
+ // Now let's populate queue control.
+ SCOPED_TRACE("queue control disabled");
+ queue_control = makeQueueConfig(PacketQueueMgr4::DEFAULT_QUEUE_TYPE4, 500, false);
+ // With queueing disabled, we should use direct reception.
+ sendReceive4Test(queue_control, false);
+ }
- // Queuing enabled, indirection reception should work.
- queue_control = makeQueueConfig(PacketQueueMgr4::DEFAULT_QUEUE_TYPE4, 500, true);
- sendReceive4Test(queue_control, true);
+ {
+ // Now let's populate queue control.
+ SCOPED_TRACE("queue control enabled");
+ // Queuing enabled, indirection reception should work.
+ queue_control = makeQueueConfig(PacketQueueMgr4::DEFAULT_QUEUE_TYPE4, 500, true);
+ sendReceive4Test(queue_control, true);
+ }
}
// Verifies that it is possible to set custom packet filter object
#include <config.h>
-#include <dhcp/packet_queue.h>
+#include <dhcp/packet_queue_ring.h>
#include <dhcp/tests/packet_queue_testutils.h>
#include <boost/shared_ptr.hpp>
return (eaten);
}
+ void queueOnePacket(Pkt4Ptr pkt, SocketInfo& sock_info) {
+ Pkt4PtrSocketInfoList pkt_list;
+ pkt_list.push_back(Pkt4PtrSocketInfoPair(pkt, sock_info));
+ ASSERT_NO_THROW(enqueuePackets(pkt_list));
+ }
+
bool drop_enabled_;
int eat_count_;
};
// Verifies use of the generic PacketQueue interface to
// construct a queue implementation.
-TEST(TestQueue4, interfaceBasics) {
+TEST(PacketQueueRing4, interfaceBasics) {
// Verify we can create a queue
- PacketQueue4Ptr q4(new TestQueue4(100));
- ASSERT_TRUE(q4);
+ PacketQueue4Ptr q(new PacketQueueRing4("kea-ring4",100));
+ ASSERT_TRUE(q);
// It should be empty.
- EXPECT_TRUE(q4->empty());
+ EXPECT_TRUE(q->empty());
// Type should match.
- EXPECT_EQ("kea-ring4", q4->getQueueType());
+ EXPECT_EQ("kea-ring4", q->getQueueType());
// Fetch the queue info and verify it has all the expected values.
- checkInfo(q4, "{ \"capacity\": 100, \"queue-type\": \"kea-ring4\", \"size\": 0 }");
+ checkInfo(q, "{ \"capacity\": 100, \"queue-type\": \"kea-ring4\", \"size\": 0 }");
}
-// Verifies the basic mechanics of the adding and
-// removing packets to and from the ring buffer.
-TEST(TestQueue4, ringTest) {
- PacketQueue4Ptr q4(new TestQueue4(3));
+// Verifies the higher level functions of queueing and dequeueing
+// from the ring buffer.
+TEST(PacketQueueRing4, enqueueDequeueTest) {
+ PacketQueue4Ptr q(new PacketQueueRing4("kea-ring4", 3));
// Fetch the queue info and verify it has all the expected values.
- checkInfo(q4, "{ \"capacity\": 3, \"queue-type\": \"kea-ring4\", \"size\": 0 }");
+ checkInfo(q, "{ \"capacity\": 3, \"queue-type\": \"kea-ring4\", \"size\": 0 }");
// Enqueue five packets. The first two should be pushed off.
SocketInfo sock1(isc::asiolink::IOAddress("127.0.0.1"), 777, 10);
+
+ Pkt4PtrSocketInfoList pkt_list;
for (int i = 1; i < 6; ++i) {
Pkt4Ptr pkt(new Pkt4(DHCPDISCOVER, 1000+i));
- ASSERT_NO_THROW(q4->enqueuePacket(pkt, sock1));
- checkIntStat(q4, "size", (i > 3 ? 3 : i));
+ pkt_list.push_back(Pkt4PtrSocketInfoPair(pkt, sock1));
}
+ // Add the packets to the queue.
+ ASSERT_NO_THROW(q->enqueuePackets(pkt_list));
+
// Fetch the queue info and verify it has all the expected values.
- checkInfo(q4, "{ \"capacity\": 3, \"queue-type\": \"kea-ring4\", \"size\": 3 }");
+ checkInfo(q, "{ \"capacity\": 3, \"queue-type\": \"kea-ring4\", \"size\": 3 }");
+
+ // We should have transids 1003,1004,1005
+ Pkt4Ptr pkt;
+ for (int i = 3; i < 6; ++i) {
+ ASSERT_NO_THROW(pkt = q->dequeuePacket());
+ ASSERT_TRUE(pkt);
+ EXPECT_EQ(1000 + i, pkt->getTransid());
+ }
+
+ // Queue should be empty.
+ ASSERT_TRUE(q->empty());
+
+ // Dequeuing should fail safely, with an empty return.
+ ASSERT_NO_THROW(pkt = q->dequeuePacket());
+ ASSERT_FALSE(pkt);
+
+ // Enqueue three more packets.
+ pkt_list.clear();
+ for (int i = 0; i < 3; ++i) {
+ Pkt4Ptr pkt(new Pkt4(DHCPDISCOVER, 1000+i));
+ pkt_list.push_back(Pkt4PtrSocketInfoPair(pkt, sock1));
+ }
+
+ ASSERT_NO_THROW(q->enqueuePackets(pkt_list));
+ checkIntStat(q, "size", 3);
+
+ // Let's flush the buffer and then verify it is empty.
+ q->clear();
+ EXPECT_TRUE(q->empty());
+ checkIntStat(q, "size", 0);
+}
+
+// Verifies peeking, pushing, and popping which
+// are unique to PacketQueueRing<> derivations.
+TEST(PacketQueueRing4, peekPushPopTest) {
+ PacketQueueRing4 q("kea-ring4", 3);
+
+ // Push five packets onto the end. The first two should get pushed off.
+ for (int i = 1; i < 6; ++i) {
+ Pkt4Ptr pkt(new Pkt4(DHCPDISCOVER, 1000+i));
+ ASSERT_NO_THROW(q.pushPacket(pkt));
+ }
+
+ // We should have three.
+ ASSERT_EQ(3, q.getSize());
// We should have transids 1005,1004,1003 (back to front)
// Peek front should be transid 1003.
Pkt4Ptr pkt;
- ASSERT_NO_THROW(pkt = q4->peek(QueueEnd::FRONT));
+ ASSERT_NO_THROW(pkt = q.peek(QueueEnd::FRONT));
ASSERT_TRUE(pkt);
EXPECT_EQ(1003, pkt->getTransid());
// Peek back should be transid 1005.
- ASSERT_NO_THROW(pkt = q4->peek(QueueEnd::BACK));
+ ASSERT_NO_THROW(pkt = q.peek(QueueEnd::BACK));
ASSERT_TRUE(pkt);
EXPECT_EQ(1005, pkt->getTransid());
// Pop front should return transid 1003.
- ASSERT_NO_THROW(pkt = q4->popPacket(QueueEnd::FRONT));
+ ASSERT_NO_THROW(pkt = q.popPacket(QueueEnd::FRONT));
ASSERT_TRUE(pkt);
EXPECT_EQ(1003, pkt->getTransid());
// Pop back should return transid 1005.
- ASSERT_NO_THROW(pkt = q4->popPacket(QueueEnd::BACK));
+ ASSERT_NO_THROW(pkt = q.popPacket(QueueEnd::BACK));
ASSERT_TRUE(pkt);
EXPECT_EQ(1005, pkt->getTransid());
// Peek front should be transid 1004.
- ASSERT_NO_THROW(pkt = q4->peek(QueueEnd::FRONT));
+ ASSERT_NO_THROW(pkt = q.peek(QueueEnd::FRONT));
ASSERT_TRUE(pkt);
EXPECT_EQ(1004, pkt->getTransid());
// Peek back should be transid 1004.
- ASSERT_NO_THROW(pkt = q4->peek(QueueEnd::BACK));
+ ASSERT_NO_THROW(pkt = q.peek(QueueEnd::BACK));
ASSERT_TRUE(pkt);
EXPECT_EQ(1004, pkt->getTransid());
// Pop front should return transid 1004.
- ASSERT_NO_THROW(pkt = q4->popPacket(QueueEnd::FRONT));
+ ASSERT_NO_THROW(pkt = q.popPacket(QueueEnd::FRONT));
ASSERT_TRUE(pkt);
EXPECT_EQ(1004, pkt->getTransid());
// Pop front should return an empty pointer.
- ASSERT_NO_THROW(pkt = q4->popPacket(QueueEnd::BACK));
- ASSERT_FALSE(pkt);
-
- // Enqueue three packets.
- for (int i = 1; i < 3; ++i) {
- Pkt4Ptr pkt(new Pkt4(DHCPDISCOVER, 1000+i));
- ASSERT_NO_THROW(q4->enqueuePacket(pkt, sock1));
- checkIntStat(q4, "size", i);
- }
-
- // Let's flush the buffer and then verify it is empty.
- q4->clear();
- EXPECT_TRUE(q4->empty());
- checkIntStat(q4, "size", 0);
-}
-
-// Verifies the higher level functions of queueing and
-// dequeueing with drop and skip logic disabled.
-TEST(TestQueue4, enqueueDequeueTest) {
- PacketQueue4Ptr q4(new TestQueue4(100));
- EXPECT_TRUE(q4->empty());
-
- SocketInfo sock1(isc::asiolink::IOAddress("127.0.0.1"), 777, 10);
-
- // Enqueue the first packet.
- Pkt4Ptr pkt(new Pkt4(DHCPDISCOVER, 1002));
- ASSERT_NO_THROW(q4->enqueuePacket(pkt, sock1));
- checkIntStat(q4, "size", 1);
-
- // Enqueue a packet onto the front.
- pkt.reset(new Pkt4(DHCPDISCOVER, 1003));
- ASSERT_NO_THROW(q4->enqueuePacket(pkt, sock1, QueueEnd::FRONT));
- checkIntStat(q4, "size", 2);
-
- // Enqueue a packet onto the back.
- pkt.reset(new Pkt4(DHCPDISCOVER, 1001));
- ASSERT_NO_THROW(q4->enqueuePacket(pkt, sock1, QueueEnd::BACK));
- checkIntStat(q4, "size", 3);
-
- // By default we dequeue from the front. We should get transid 1003.
- ASSERT_NO_THROW(pkt = q4->dequeuePacket());
- ASSERT_TRUE(pkt);
- EXPECT_EQ(1003, pkt->getTransid());
-
- // Dequeue from the back, we should get transid 1001.
- ASSERT_NO_THROW(pkt = q4->dequeuePacket(QueueEnd::BACK));
- ASSERT_TRUE(pkt);
- EXPECT_EQ(1001, pkt->getTransid());
-
- // Dequeue from the front, we should get transid 1002.
- ASSERT_NO_THROW(pkt = q4->dequeuePacket(QueueEnd::FRONT));
- ASSERT_TRUE(pkt);
- EXPECT_EQ(1002, pkt->getTransid());
-
- // Queue should be empty.
- ASSERT_NO_THROW(pkt = q4->dequeuePacket());
+ ASSERT_NO_THROW(pkt = q.popPacket(QueueEnd::BACK));
ASSERT_FALSE(pkt);
}
// This accesses it's queue instance as a TestQueue4, rather than
// a PacketQueue4Ptr, to provide access to TestQueue4 specifics.
TEST(TestQueue4, shouldDropPacketTest) {
- TestQueue4 q4(100);
- EXPECT_TRUE(q4.empty());
- ASSERT_FALSE(q4.drop_enabled_);
- ASSERT_EQ(0, q4.eat_count_);
+ TestQueue4 q(100);
+ EXPECT_TRUE(q.empty());
+ ASSERT_FALSE(q.drop_enabled_);
+ ASSERT_EQ(0, q.eat_count_);
- SocketInfo sockEven(isc::asiolink::IOAddress("127.0.0.1"), 888, 10);
- SocketInfo sockOdd(isc::asiolink::IOAddress("127.0.0.1"), 777, 11);
+ SocketInfo sock_even(isc::asiolink::IOAddress("127.0.0.1"), 888, 10);
+ SocketInfo sock_odd(isc::asiolink::IOAddress("127.0.0.1"), 777, 11);
// Drop is not enabled.
// We should be able to enqueue a packet with even numbered values.
+ Pkt4PtrSocketInfoList pkt_list;
+
Pkt4Ptr pkt(new Pkt4(DHCPDISCOVER, 1002));
- ASSERT_NO_THROW(q4.enqueuePacket(pkt, sockEven));
- EXPECT_EQ(1, q4.getSize());
+ q.queueOnePacket(pkt, sock_even);
+ ASSERT_EQ(1, q.getSize());
// We should be able to enqueue a packet with odd numbered values.
pkt.reset(new Pkt4(DHCPDISCOVER, 1003));
- ASSERT_NO_THROW(q4.enqueuePacket(pkt, sockOdd));
- EXPECT_EQ(2, q4.getSize());
+ q.queueOnePacket(pkt, sock_odd);
+ ASSERT_EQ(2, q.getSize());
// Enable drop logic.
- q4.drop_enabled_ = true;
+ q.drop_enabled_ = true;
// We should not be able to add one with an even-numbered transid.
pkt.reset(new Pkt4(DHCPDISCOVER, 1004));
- ASSERT_NO_THROW(q4.enqueuePacket(pkt, sockOdd));
- EXPECT_EQ(2, q4.getSize());
+ q.queueOnePacket(pkt, sock_odd);
+ ASSERT_EQ(2, q.getSize());
// We should not be able to add one with from even-numbered port.
pkt.reset(new Pkt4(DHCPDISCOVER, 1005));
- ASSERT_NO_THROW(q4.enqueuePacket(pkt, sockEven));
- EXPECT_EQ(2, q4.getSize());
+ q.queueOnePacket(pkt, sock_even);
+ EXPECT_EQ(2, q.getSize());
// We should be able to add one with an odd-numbered values.
pkt.reset(new Pkt4(DHCPDISCOVER, 1007));
- ASSERT_NO_THROW(q4.enqueuePacket(pkt, sockOdd));
- EXPECT_EQ(3, q4.getSize());
+ q.queueOnePacket(pkt, sock_odd);
+ EXPECT_EQ(3, q.getSize());
// Dequeue them and make sure they are as expected: 1002,1003, and 1007.
- ASSERT_NO_THROW(pkt = q4.dequeuePacket());
+ ASSERT_NO_THROW(pkt = q.dequeuePacket());
ASSERT_TRUE(pkt);
EXPECT_EQ(1002, pkt->getTransid());
- ASSERT_NO_THROW(pkt = q4.dequeuePacket());
+ ASSERT_NO_THROW(pkt = q.dequeuePacket());
ASSERT_TRUE(pkt);
EXPECT_EQ(1003, pkt->getTransid());
- ASSERT_NO_THROW(pkt = q4.dequeuePacket());
+ ASSERT_NO_THROW(pkt = q.dequeuePacket());
ASSERT_TRUE(pkt);
EXPECT_EQ(1007, pkt->getTransid());
// Queue should be empty.
- ASSERT_NO_THROW(pkt = q4.dequeuePacket());
+ ASSERT_NO_THROW(pkt = q.dequeuePacket());
ASSERT_FALSE(pkt);
}
// This accesses it's queue instance as a TestQueue4, rather than
// a PacketQueue4Ptr, to provide access to TestQueue4 specifics.
TEST(TestQueue4, eatPacketsTest) {
- TestQueue4 q4(100);
- EXPECT_TRUE(q4.empty());
- ASSERT_FALSE(q4.drop_enabled_);
- ASSERT_EQ(0, q4.eat_count_);
+ TestQueue4 q(100);
+ EXPECT_TRUE(q.empty());
+ ASSERT_FALSE(q.drop_enabled_);
+ ASSERT_EQ(0, q.eat_count_);
SocketInfo sock(isc::asiolink::IOAddress("127.0.0.1"), 888, 10);
// Let's add five packets.
for (int i = 1; i < 6; ++i) {
pkt.reset(new Pkt4(DHCPDISCOVER, 1000 + i));
- ASSERT_NO_THROW(q4.enqueuePacket(pkt, sock));
- EXPECT_EQ(i, q4.getSize());
+ q.queueOnePacket(pkt, sock);
+ ASSERT_EQ(i, q.getSize());
}
- // Setting eat count to two and dequeuing (from the front, by default),
- // should discard 1001 and 1002, resulting in a dequeue of 1003.
- q4.eat_count_ = 2;
- ASSERT_NO_THROW(pkt = q4.dequeuePacket());
+ // Setting eat count to two and dequeuing should discard 1001
+ // and 1002, resulting in a dequeue of 1003.
+ q.eat_count_ = 2;
+ ASSERT_NO_THROW(pkt = q.dequeuePacket());
ASSERT_TRUE(pkt);
EXPECT_EQ(1003, pkt->getTransid());
- EXPECT_EQ(2, q4.getSize());
-
- // Setting eat count to one and dequeing from the back, should discard
- // 1005 and dequeue 104.
- q4.eat_count_ = 1;
- ASSERT_NO_THROW(pkt = q4.dequeuePacket(QueueEnd::BACK));
- ASSERT_TRUE(pkt);
- EXPECT_EQ(1004, pkt->getTransid());
- EXPECT_EQ(0, q4.getSize());
+ EXPECT_EQ(2, q.getSize());
}
} // end of anonymous namespace
#include <config.h>
#include <dhcp/dhcp6.h>
-#include <dhcp/packet_queue.h>
+#include <dhcp/packet_queue_ring.h>
#include <dhcp/tests/packet_queue_testutils.h>
#include <boost/shared_ptr.hpp>
return (eaten);
}
+ void queueOnePacket(Pkt6Ptr pkt, SocketInfo& sock_info) {
+ Pkt6PtrSocketInfoList pkt_list;
+ pkt_list.push_back(Pkt6PtrSocketInfoPair(pkt, sock_info));
+ ASSERT_NO_THROW(enqueuePackets(pkt_list));
+ }
+
bool drop_enabled_;
int eat_count_;
};
// Verifies use of the generic PacketQueue interface to
// construct a queue implementation.
-TEST(TestQueue6, interfaceBasics) {
+TEST(PacketQueueRing6, interfaceBasics) {
// Verify we can create a queue
- PacketQueue6Ptr q6(new TestQueue6(100));
- ASSERT_TRUE(q6);
+ PacketQueue6Ptr q(new PacketQueueRing6("kea-ring6",100));
+ ASSERT_TRUE(q);
// It should be empty.
- EXPECT_TRUE(q6->empty());
+ EXPECT_TRUE(q->empty());
// Type should match.
- EXPECT_EQ("kea-ring6", q6->getQueueType());
+ EXPECT_EQ("kea-ring6", q->getQueueType());
// Fetch the queue info and verify it has all the expected values.
- checkInfo(q6, "{ \"capacity\": 100, \"queue-type\": \"kea-ring6\", \"size\": 0 }");
+ checkInfo(q, "{ \"capacity\": 100, \"queue-type\": \"kea-ring6\", \"size\": 0 }");
}
-// Verifies the basic mechanics of the adding and
-// removing packets to and from the ring buffer.
-TEST(TestQueue6, ringTest) {
- PacketQueue6Ptr q6(new TestQueue6(3));
+// Verifies the higher level functions of queueing and dequeueing
+// from the ring buffer.
+TEST(PacketQueueRing6, enqueueDequeueTest) {
+ PacketQueue6Ptr q(new PacketQueueRing6("kea-ring6", 3));
// Fetch the queue info and verify it has all the expected values.
- checkInfo(q6, "{ \"capacity\": 3, \"queue-type\": \"kea-ring6\", \"size\": 0 }");
+ checkInfo(q, "{ \"capacity\": 3, \"queue-type\": \"kea-ring6\", \"size\": 0 }");
// Enqueue five packets. The first two should be pushed off.
SocketInfo sock1(isc::asiolink::IOAddress("127.0.0.1"), 777, 10);
+
+ Pkt6PtrSocketInfoList pkt_list;
for (int i = 1; i < 6; ++i) {
Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 1000+i));
- ASSERT_NO_THROW(q6->enqueuePacket(pkt, sock1));
- checkIntStat(q6, "size", (i > 3 ? 3 : i));
+ pkt_list.push_back(Pkt6PtrSocketInfoPair(pkt, sock1));
}
+ // Add the packets to the queue.
+ ASSERT_NO_THROW(q->enqueuePackets(pkt_list));
+
// Fetch the queue info and verify it has all the expected values.
- checkInfo(q6, "{ \"capacity\": 3, \"queue-type\": \"kea-ring6\", \"size\": 3 }");
+ checkInfo(q, "{ \"capacity\": 3, \"queue-type\": \"kea-ring6\", \"size\": 3 }");
+
+ // We should have transids 1003,1004,1005
+ Pkt6Ptr pkt;
+ for (int i = 3; i < 6; ++i) {
+ ASSERT_NO_THROW(pkt = q->dequeuePacket());
+ ASSERT_TRUE(pkt);
+ EXPECT_EQ(1000 + i, pkt->getTransid());
+ }
+
+ // Queue should be empty.
+ ASSERT_TRUE(q->empty());
+
+ // Dequeuing should fail safely, with an empty return.
+ ASSERT_NO_THROW(pkt = q->dequeuePacket());
+ ASSERT_FALSE(pkt);
+
+ // Enqueue three more packets.
+ pkt_list.clear();
+ for (int i = 0; i < 3; ++i) {
+ Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 1000+i));
+ pkt_list.push_back(Pkt6PtrSocketInfoPair(pkt, sock1));
+ }
+
+ ASSERT_NO_THROW(q->enqueuePackets(pkt_list));
+ checkIntStat(q, "size", 3);
+
+ // Let's flush the buffer and then verify it is empty.
+ q->clear();
+ EXPECT_TRUE(q->empty());
+ checkIntStat(q, "size", 0);
+}
+
+// Verifies peeking, pushing, and popping which
+// are unique to PacketQueueRing<> derivations.
+TEST(PacketQueueRing6, peekPushPopTest) {
+ PacketQueueRing6 q("kea-ring6", 3);
+
+ // Push five packets onto the end. The first two should get pushed off.
+ for (int i = 1; i < 6; ++i) {
+ Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 1000+i));
+ ASSERT_NO_THROW(q.pushPacket(pkt));
+ }
+
+ // We should have three.
+ ASSERT_EQ(3, q.getSize());
// We should have transids 1005,1004,1003 (back to front)
// Peek front should be transid 1003.
Pkt6Ptr pkt;
- ASSERT_NO_THROW(pkt = q6->peek(QueueEnd::FRONT));
+ ASSERT_NO_THROW(pkt = q.peek(QueueEnd::FRONT));
ASSERT_TRUE(pkt);
EXPECT_EQ(1003, pkt->getTransid());
// Peek back should be transid 1005.
- ASSERT_NO_THROW(pkt = q6->peek(QueueEnd::BACK));
+ ASSERT_NO_THROW(pkt = q.peek(QueueEnd::BACK));
ASSERT_TRUE(pkt);
EXPECT_EQ(1005, pkt->getTransid());
// Pop front should return transid 1003.
- ASSERT_NO_THROW(pkt = q6->popPacket(QueueEnd::FRONT));
+ ASSERT_NO_THROW(pkt = q.popPacket(QueueEnd::FRONT));
ASSERT_TRUE(pkt);
EXPECT_EQ(1003, pkt->getTransid());
// Pop back should return transid 1005.
- ASSERT_NO_THROW(pkt = q6->popPacket(QueueEnd::BACK));
+ ASSERT_NO_THROW(pkt = q.popPacket(QueueEnd::BACK));
ASSERT_TRUE(pkt);
EXPECT_EQ(1005, pkt->getTransid());
// Peek front should be transid 1004.
- ASSERT_NO_THROW(pkt = q6->peek(QueueEnd::FRONT));
+ ASSERT_NO_THROW(pkt = q.peek(QueueEnd::FRONT));
ASSERT_TRUE(pkt);
EXPECT_EQ(1004, pkt->getTransid());
// Peek back should be transid 1004.
- ASSERT_NO_THROW(pkt = q6->peek(QueueEnd::BACK));
+ ASSERT_NO_THROW(pkt = q.peek(QueueEnd::BACK));
ASSERT_TRUE(pkt);
EXPECT_EQ(1004, pkt->getTransid());
// Pop front should return transid 1004.
- ASSERT_NO_THROW(pkt = q6->popPacket(QueueEnd::FRONT));
+ ASSERT_NO_THROW(pkt = q.popPacket(QueueEnd::FRONT));
ASSERT_TRUE(pkt);
EXPECT_EQ(1004, pkt->getTransid());
// Pop front should return an empty pointer.
- ASSERT_NO_THROW(pkt = q6->popPacket(QueueEnd::BACK));
- ASSERT_FALSE(pkt);
-
- // Enqueue three packets.
- for (int i = 1; i < 3; ++i) {
- Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 1000+i));
- ASSERT_NO_THROW(q6->enqueuePacket(pkt, sock1));
- checkIntStat(q6, "size", i);
- }
-
- // Let's flush the buffer and then verify it is empty.
- q6->clear();
- EXPECT_TRUE(q6->empty());
- checkIntStat(q6, "size", 0);
-}
-
-// Verifies the higher level functions of queueing and
-// dequeueing with drop and skip logic disabled.
-TEST(TestQueue6, enqueueDequeueTest) {
- PacketQueue6Ptr q6(new TestQueue6(100));
- EXPECT_TRUE(q6->empty());
-
- SocketInfo sock1(isc::asiolink::IOAddress("127.0.0.1"), 777, 10);
-
- // Enqueue the first packet.
- Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 1002));
- ASSERT_NO_THROW(q6->enqueuePacket(pkt, sock1));
- checkIntStat(q6, "size", 1);
-
- // Enqueue a packet onto the front.
- pkt.reset(new Pkt6(DHCPV6_SOLICIT, 1003));
- ASSERT_NO_THROW(q6->enqueuePacket(pkt, sock1, QueueEnd::FRONT));
- checkIntStat(q6, "size", 2);
-
- // Enqueue a packet onto the back.
- pkt.reset(new Pkt6(DHCPV6_SOLICIT, 1001));
- ASSERT_NO_THROW(q6->enqueuePacket(pkt, sock1, QueueEnd::BACK));
- checkIntStat(q6, "size", 3);
-
- // By default we dequeue from the front. We should get transid 1003.
- ASSERT_NO_THROW(pkt = q6->dequeuePacket());
- ASSERT_TRUE(pkt);
- EXPECT_EQ(1003, pkt->getTransid());
-
- // Dequeue from the back, we should get transid 1001.
- ASSERT_NO_THROW(pkt = q6->dequeuePacket(QueueEnd::BACK));
- ASSERT_TRUE(pkt);
- EXPECT_EQ(1001, pkt->getTransid());
-
- // Dequeue from the front, we should get transid 1002.
- ASSERT_NO_THROW(pkt = q6->dequeuePacket(QueueEnd::FRONT));
- ASSERT_TRUE(pkt);
- EXPECT_EQ(1002, pkt->getTransid());
-
- // Queue should be empty.
- ASSERT_NO_THROW(pkt = q6->dequeuePacket());
+ ASSERT_NO_THROW(pkt = q.popPacket(QueueEnd::BACK));
ASSERT_FALSE(pkt);
}
// This accesses it's queue instance as a TestQueue6, rather than
// a PacketQueue6Ptr, to provide access to TestQueue6 specifics.
TEST(TestQueue6, shouldDropPacketTest) {
- TestQueue6 q6(100);
- EXPECT_TRUE(q6.empty());
- ASSERT_FALSE(q6.drop_enabled_);
- ASSERT_EQ(0, q6.eat_count_);
+ TestQueue6 q(100);
+ EXPECT_TRUE(q.empty());
+ ASSERT_FALSE(q.drop_enabled_);
+ ASSERT_EQ(0, q.eat_count_);
- SocketInfo sockEven(isc::asiolink::IOAddress("127.0.0.1"), 888, 10);
- SocketInfo sockOdd(isc::asiolink::IOAddress("127.0.0.1"), 777, 11);
+ SocketInfo sock_even(isc::asiolink::IOAddress("127.0.0.1"), 888, 10);
+ SocketInfo sock_odd(isc::asiolink::IOAddress("127.0.0.1"), 777, 11);
// Drop is not enabled.
// We should be able to enqueue a packet with even numbered values.
+ Pkt6PtrSocketInfoList pkt_list;
+
Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 1002));
- ASSERT_NO_THROW(q6.enqueuePacket(pkt, sockEven));
- EXPECT_EQ(1, q6.getSize());
+ q.queueOnePacket(pkt, sock_even);
+ ASSERT_EQ(1, q.getSize());
// We should be able to enqueue a packet with odd numbered values.
pkt.reset(new Pkt6(DHCPV6_SOLICIT, 1003));
- ASSERT_NO_THROW(q6.enqueuePacket(pkt, sockOdd));
- EXPECT_EQ(2, q6.getSize());
+ q.queueOnePacket(pkt, sock_odd);
+ ASSERT_EQ(2, q.getSize());
// Enable drop logic.
- q6.drop_enabled_ = true;
+ q.drop_enabled_ = true;
// We should not be able to add one with an even-numbered transid.
pkt.reset(new Pkt6(DHCPV6_SOLICIT, 1004));
- ASSERT_NO_THROW(q6.enqueuePacket(pkt, sockOdd));
- EXPECT_EQ(2, q6.getSize());
+ q.queueOnePacket(pkt, sock_odd);
+ ASSERT_EQ(2, q.getSize());
// We should not be able to add one with from even-numbered port.
pkt.reset(new Pkt6(DHCPV6_SOLICIT, 1005));
- ASSERT_NO_THROW(q6.enqueuePacket(pkt, sockEven));
- EXPECT_EQ(2, q6.getSize());
+ q.queueOnePacket(pkt, sock_even);
+ EXPECT_EQ(2, q.getSize());
// We should be able to add one with an odd-numbered values.
pkt.reset(new Pkt6(DHCPV6_SOLICIT, 1007));
- ASSERT_NO_THROW(q6.enqueuePacket(pkt, sockOdd));
- EXPECT_EQ(3, q6.getSize());
+ q.queueOnePacket(pkt, sock_odd);
+ EXPECT_EQ(3, q.getSize());
// Dequeue them and make sure they are as expected: 1002,1003, and 1007.
- ASSERT_NO_THROW(pkt = q6.dequeuePacket());
+ ASSERT_NO_THROW(pkt = q.dequeuePacket());
ASSERT_TRUE(pkt);
EXPECT_EQ(1002, pkt->getTransid());
- ASSERT_NO_THROW(pkt = q6.dequeuePacket());
+ ASSERT_NO_THROW(pkt = q.dequeuePacket());
ASSERT_TRUE(pkt);
EXPECT_EQ(1003, pkt->getTransid());
- ASSERT_NO_THROW(pkt = q6.dequeuePacket());
+ ASSERT_NO_THROW(pkt = q.dequeuePacket());
ASSERT_TRUE(pkt);
EXPECT_EQ(1007, pkt->getTransid());
// Queue should be empty.
- ASSERT_NO_THROW(pkt = q6.dequeuePacket());
+ ASSERT_NO_THROW(pkt = q.dequeuePacket());
ASSERT_FALSE(pkt);
}
// This accesses it's queue instance as a TestQueue6, rather than
// a PacketQueue6Ptr, to provide access to TestQueue6 specifics.
TEST(TestQueue6, eatPacketsTest) {
- TestQueue6 q6(100);
- EXPECT_TRUE(q6.empty());
- ASSERT_FALSE(q6.drop_enabled_);
- ASSERT_EQ(0, q6.eat_count_);
+ TestQueue6 q(100);
+ EXPECT_TRUE(q.empty());
+ ASSERT_FALSE(q.drop_enabled_);
+ ASSERT_EQ(0, q.eat_count_);
SocketInfo sock(isc::asiolink::IOAddress("127.0.0.1"), 888, 10);
// Let's add five packets.
for (int i = 1; i < 6; ++i) {
pkt.reset(new Pkt6(DHCPV6_SOLICIT, 1000 + i));
- ASSERT_NO_THROW(q6.enqueuePacket(pkt, sock));
- EXPECT_EQ(i, q6.getSize());
+ q.queueOnePacket(pkt, sock);
+ ASSERT_EQ(i, q.getSize());
}
- // Setting eat count to two and dequeuing (from the front, by default),
- // should discard 1001 and 1002, resulting in a dequeue of 1003.
- q6.eat_count_ = 2;
- ASSERT_NO_THROW(pkt = q6.dequeuePacket());
+ // Setting eat count to two and dequeuing should discard 1001
+ // and 1002, resulting in a dequeue of 1003.
+ q.eat_count_ = 2;
+ ASSERT_NO_THROW(pkt = q.dequeuePacket());
ASSERT_TRUE(pkt);
EXPECT_EQ(1003, pkt->getTransid());
- EXPECT_EQ(2, q6.getSize());
-
- // Setting eat count to one and dequeing from the back, should discard
- // 1005 and dequeue 104.
- q6.eat_count_ = 1;
- ASSERT_NO_THROW(pkt = q6.dequeuePacket(QueueEnd::BACK));
- ASSERT_TRUE(pkt);
- EXPECT_EQ(1004, pkt->getTransid());
- EXPECT_EQ(0, q6.getSize());
+ EXPECT_EQ(2, q.getSize());
}
} // end of anonymous namespace
#include <config.h>
+#include <dhcp/packet_queue_ring.h>
#include <dhcp/packet_queue_mgr4.h>
#include <dhcp/tests/packet_queue_testutils.h>
#include <config.h>
+#include <dhcp/packet_queue_ring.h>
#include <dhcp/packet_queue_mgr6.h>
#include <dhcp/tests/packet_queue_testutils.h>