#include <dhcp/pkt_filter_inet6.h>
#include <exceptions/exceptions.h>
#include <util/io/pktinfo_utilities.h>
+#include <util/multi_threading_mgr.h>
-#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/bind.hpp>
#include <cstring>
#include <errno.h>
#include <fstream>
+#include <limits>
#include <sstream>
#include <arpa/inet.h>
flag_multicast_(false), flag_broadcast_(false), flags_(0),
inactive4_(false), inactive6_(false)
{
+ if ((ifindex_ < 0) || (ifindex_ > std::numeric_limits<int32_t>::max())) {
+ isc_throw(OutOfRange, "Interface index must be in 0.." <<
+ std::numeric_limits<int32_t>::max());
+ }
memset(mac_, 0, sizeof(mac_));
}
}
IfaceMgr::IfaceMgr()
- :packet_filter_(new PktFilterInet()),
- packet_filter6_(new PktFilterInet6()),
- test_mode_(false),
- allow_loopback_(false) {
+ : fail_on_index_not_found_(false),
+ packet_filter_(new PktFilterInet()),
+ packet_filter6_(new PktFilterInet6()),
+ test_mode_(false),
+ allow_loopback_(false) {
// Ensure that PQMs have been created to guarantee we have
// default packet queues in place.
}
void Iface::addUnicast(const isc::asiolink::IOAddress& addr) {
- BOOST_FOREACH(Address a, unicasts_) {
+ for (Address a : unicasts_) {
if (a.get() == addr) {
isc_throw(BadValue, "Address " << addr
<< " already defined on the " << name_ << " interface.");
Iface::getAddress4(isc::asiolink::IOAddress& address) const {
// Iterate over existing addresses assigned to the interface.
// Try to find the one that is IPv4.
- BOOST_FOREACH(Address addr, getAddresses()) {
+ for (Address addr : getAddresses()) {
// If address is IPv4, we assign it to the function argument
// and return true.
if (addr.get().isV4()) {
bool
Iface::hasAddress(const isc::asiolink::IOAddress& address) const {
- BOOST_FOREACH(Address addr, getAddresses()) {
+ for (Address addr : getAddresses()) {
if (address == addr.get()) {
return (true);
}
unsigned int
Iface::countActive4() const {
uint16_t count = 0;
- BOOST_FOREACH(Address addr, addrs_) {
+ for (Address addr : addrs_) {
if (!addr.unspecified() && addr.get().isV4()) {
++count;
}
// Stops the receiver thread if there is one.
stopDHCPReceiver();
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
+ for (IfacePtr iface : ifaces_) {
iface->closeSockets();
}
}
<< socketfd);
}
std::lock_guard<std::mutex> lock(callbacks_mutex_);
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ for (SocketCallbackInfo s : callbacks_) {
// There's such a socket description there already.
// Update the callback and we're done
if (s.socket_ == socketfd) {
bool
IfaceMgr::hasOpenSocket(const uint16_t family) const {
// Iterate over all interfaces and search for open sockets.
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
- BOOST_FOREACH(SocketInfo sock, iface->getSockets()) {
+ for (IfacePtr iface : ifaces_) {
+ for (SocketInfo sock : iface->getSockets()) {
// Check if the socket matches specified family.
if (sock.family_ == family) {
// There is at least one socket open, so return.
bool
IfaceMgr::hasOpenSocket(const IOAddress& addr) const {
// Iterate over all interfaces and search for open sockets.
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
- BOOST_FOREACH(SocketInfo sock, iface->getSockets()) {
+ for (IfacePtr iface : ifaces_) {
+ for (SocketInfo sock : iface->getSockets()) {
// Check if the socket address matches the specified address or
// if address is unspecified (in6addr_any).
if (sock.addr_ == addr) {
// Handle the case that the address is unspecified (any).
// In this case, we should check if the specified address
// belongs to any of the interfaces.
- BOOST_FOREACH(Iface::Address a, iface->getAddresses()) {
+ for (Iface::Address a : iface->getAddresses()) {
if (addr == a.get()) {
return (true);
}
int count = 0;
int bcast_num = 0;
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
+ for (IfacePtr iface : ifaces_) {
// If the interface is inactive, there is nothing to do. Simply
// proceed to the next detected interface.
if (iface->inactive4_) {
}
}
- BOOST_FOREACH(Iface::Address addr, iface->getAddresses()) {
+ for (Iface::Address addr : iface->getAddresses()) {
// Skip non-IPv4 addresses and those that weren't selected..
if (addr.unspecified() || !addr.get().isV4()) {
continue;
IfaceMgrErrorMsgCallback error_handler) {
int count = 0;
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
+ for (IfacePtr iface : ifaces_) {
if (iface->inactive6_) {
continue;
}
// Open unicast sockets if there are any unicast addresses defined
- BOOST_FOREACH(Iface::Address addr, iface->getUnicasts()) {
+ for (Iface::Address addr : iface->getUnicasts()) {
try {
openSocket(iface->getName(), addr, port);
}
- BOOST_FOREACH(Iface::Address addr, iface->getAddresses()) {
+ for (Iface::Address addr : iface->getAddresses()) {
// Skip all but V6 addresses.
if (!addr.get().isV6()) {
void
IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
+ for (IfacePtr iface : ifaces_) {
const Iface::AddressCollection& addrs = iface->getAddresses();
out << "Detected interface " << iface->getFullName()
<< ")" << endl;
out << " " << addrs.size() << " addr(s):";
- BOOST_FOREACH(Iface::Address addr, addrs) {
+ for (Iface::Address addr : addrs) {
out << " " << addr.get().toText();
}
out << endl;
}
IfacePtr
-IfaceMgr::getIface(int ifindex) {
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
- if (iface->getIndex() == ifindex)
- return (iface);
+IfaceCollection::getIface(uint32_t ifindex) {
+ return (getIfaceInternal(ifindex, MultiThreadingMgr::instance().getMode()));
+}
+
+
+IfacePtr
+IfaceCollection::getIface(const std::string& ifname) {
+ return (getIfaceInternal(ifname, MultiThreadingMgr::instance().getMode()));
+}
+
+IfacePtr
+IfaceCollection::getIfaceInternal(uint32_t ifindex, bool need_lock) {
+ if (need_lock) {
+ lock_guard<mutex> lock(mutex_);
+ if (cache_ && (cache_->getIndex() == ifindex)) {
+ return (cache_);
+ }
+ } else {
+ if (cache_ && (cache_->getIndex() == ifindex)) {
+ return (cache_);
+ }
+ }
+ const auto& idx = ifaces_container_.get<1>();
+ auto it = idx.find(ifindex);
+ if (it == idx.end()) {
+ return (IfacePtr()); // not found
+ }
+ if (need_lock) {
+ lock_guard<mutex> lock(mutex_);
+ cache_ = *it;
+ return (cache_);
+ } else {
+ lock_guard<mutex> lock(mutex_);
+ cache_ = *it;
+ return (cache_);
}
+}
- return (IfacePtr()); // not found
+IfacePtr
+IfaceCollection::getIfaceInternal(const std::string& ifname, bool need_lock) {
+ if (need_lock) {
+ lock_guard<mutex> lock(mutex_);
+ if (cache_ && (cache_->getName() == ifname)) {
+ return (cache_);
+ }
+ } else {
+ if (cache_ && (cache_->getName() == ifname)) {
+ return (cache_);
+ }
+ }
+ const auto& idx = ifaces_container_.get<2>();
+ auto it = idx.find(ifname);
+ if (it == idx.end()) {
+ return (IfacePtr()); // not found
+ }
+ if (need_lock) {
+ lock_guard<mutex> lock(mutex_);
+ cache_ = *it;
+ return (cache_);
+ } else {
+ lock_guard<mutex> lock(mutex_);
+ cache_ = *it;
+ return (cache_);
+ }
}
IfacePtr
-IfaceMgr::getIface(const std::string& ifname) {
- std::cerr << "getIface(name) unefficient\n";
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
- if (iface->getName() == ifname)
- return (iface);
+IfaceMgr::getIface(int ifindex) {
+ if ((ifindex < 0) || (ifindex > std::numeric_limits<int32_t>::max())) {
+ return (IfacePtr()); // out of range
}
+ return (ifaces_.getIface(ifindex));
+}
- return (IfacePtr()); // not found
+IfacePtr
+IfaceMgr::getIface(const std::string& ifname) {
+ if (ifname.empty()) {
+ return (IfacePtr()); // empty
+ }
+ return (ifaces_.getIface(ifname));
}
IfacePtr
IfaceMgr::getIface(const PktPtr& pkt) {
- IfacePtr iface = getIface(pkt->getIndex());
+ IfacePtr iface;
+ if (pkt->indexSet()) {
+ iface = getIface(pkt->getIndex());
+ if (fail_on_index_not_found_) {
+ return (iface);
+ }
+ }
if (!iface) {
iface = getIface(pkt->getIface());
}
void
IfaceMgr::clearUnicasts() {
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
+ for (IfacePtr iface : ifaces_) {
iface->clearUnicasts();
}
}
const uint16_t port,
const uint8_t family) {
// Search for specified interface among detected interfaces.
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
+ for (IfacePtr iface : ifaces_) {
if ((iface->getFullName() != ifname) &&
(iface->getName() != ifname)) {
continue;
const uint16_t port) {
// Search through detected interfaces and addresses to match
// local address we got.
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
- BOOST_FOREACH(Iface::Address a, iface->getAddresses()) {
+ for (IfacePtr iface : ifaces_) {
+ for (Iface::Address a : iface->getAddresses()) {
// Local address must match one of the addresses
// on detected interfaces. If it does, we have
{
std::lock_guard<std::mutex> lock(callbacks_mutex_);
if (!callbacks_.empty()) {
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ for (SocketCallbackInfo s : callbacks_) {
// Add this socket to listening set
addFDtoSet(s.socket_, maxfd, &sockets);
}
bool found = false;
{
std::lock_guard<std::mutex> lock(callbacks_mutex_);
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ for (SocketCallbackInfo s : callbacks_) {
if (!FD_ISSET(s.socket_, &sockets)) {
continue;
}
" one million microseconds");
}
boost::scoped_ptr<SocketInfo> candidate;
- IfacePtr iface;
fd_set sockets;
int maxfd = 0;
/// @todo: marginal performance optimization. We could create the set once
/// and then use its copy for select(). Please note that select() modifies
/// provided set to indicated which sockets have something to read.
- BOOST_FOREACH(iface, ifaces_) {
- BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+ for (IfacePtr iface : ifaces_) {
+ for (SocketInfo s : iface->getSockets()) {
// Only deal with IPv4 addresses.
if (s.addr_.isV4()) {
// Add this socket to listening set
{
std::lock_guard<std::mutex> lock(callbacks_mutex_);
if (!callbacks_.empty()) {
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ for (SocketCallbackInfo s : callbacks_) {
// Add this socket to listening set
addFDtoSet(s.socket_, maxfd, &sockets);
}
bool found = false;
{
std::lock_guard<std::mutex> lock(callbacks_mutex_);
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ for (SocketCallbackInfo s : callbacks_) {
if (!FD_ISSET(s.socket_, &sockets)) {
continue;
}
}
// Let's find out which interface/socket has the data
- BOOST_FOREACH(iface, ifaces_) {
- BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+ IfacePtr recv_if;
+ for (IfacePtr iface : ifaces_) {
+ for (SocketInfo s : iface->getSockets()) {
if (FD_ISSET(s.sockfd_, &sockets)) {
candidate.reset(new SocketInfo(s));
break;
}
}
if (candidate) {
+ recv_if = iface;
break;
}
}
- if (!candidate) {
+ if (!candidate || !recv_if) {
isc_throw(SocketReadError, "received data over unknown socket");
}
// Now we have a socket, let's get some data from it!
// Assuming that packet filter is not null, because its modifier checks it.
- return (packet_filter_->receive(*iface, *candidate));
+ return (packet_filter_->receive(*recv_if, *candidate));
}
Pkt6Ptr
/// @todo: marginal performance optimization. We could create the set once
/// and then use its copy for select(). Please note that select() modifies
/// provided set to indicated which sockets have something to read.
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
- BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+ for (IfacePtr iface : ifaces_) {
+ for (SocketInfo s : iface->getSockets()) {
// Only deal with IPv6 addresses.
if (s.addr_.isV6()) {
// Add this socket to listening set
{
std::lock_guard<std::mutex> lock(callbacks_mutex_);
if (!callbacks_.empty()) {
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ for (SocketCallbackInfo s : callbacks_) {
// Add this socket to listening set
addFDtoSet(s.socket_, maxfd, &sockets);
}
bool found = false;
{
std::lock_guard<std::mutex> lock(callbacks_mutex_);
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ for (SocketCallbackInfo s : callbacks_) {
if (!FD_ISSET(s.socket_, &sockets)) {
continue;
}
}
// Let's find out which interface/socket has the data
- BOOST_FOREACH(IfacePtr iface, ifaces_) {
- BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+ for (IfacePtr iface : ifaces_) {
+ for (SocketInfo s : iface->getSockets()) {
if (FD_ISSET(s.sockfd_, &sockets)) {
candidate.reset(new SocketInfo(s));
break;
{
std::lock_guard<std::mutex> lock(callbacks_mutex_);
if (!callbacks_.empty()) {
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ for (SocketCallbackInfo s : callbacks_) {
// Add this socket to listening set
addFDtoSet(s.socket_, maxfd, &sockets);
}
bool found = false;
{
std::lock_guard<std::mutex> lock(callbacks_mutex_);
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ for (SocketCallbackInfo s : callbacks_) {
if (!FD_ISSET(s.socket_, &sockets)) {
continue;
}
void
IfaceMgr::receiveDHCP4Packets() {
- IfacePtr iface;
fd_set sockets;
int maxfd = 0;
addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::TERMINATE), maxfd, &sockets);
// Add Interface sockets.
- BOOST_FOREACH(iface, ifaces_) {
- BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+ for (IfacePtr iface : ifaces_) {
+ for (SocketInfo s : iface->getSockets()) {
// Only deal with IPv4 addresses.
if (s.addr_.isV4()) {
// Add this socket to listening set.
}
// Let's find out which interface/socket has data.
- BOOST_FOREACH(iface, ifaces_) {
- BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+ for (IfacePtr iface : ifaces_) {
+ for (SocketInfo s : iface->getSockets()) {
if (FD_ISSET(s.sockfd_, &sockets)) {
receiveDHCP4Packet(*iface, s);
// Can take time so check one more time the watch socket.
void
IfaceMgr::receiveDHCP6Packets() {
- IfacePtr iface;
fd_set sockets;
int maxfd = 0;
addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::TERMINATE), maxfd, &sockets);
// Add Interface sockets.
- BOOST_FOREACH(iface, ifaces_) {
- BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+ for (IfacePtr iface : ifaces_) {
+ for (SocketInfo s : iface->getSockets()) {
// Only deal with IPv6 addresses.
if (s.addr_.isV6()) {
// Add this socket to listening set.
}
// Let's find out which interface/socket has data.
- BOOST_FOREACH(iface, ifaces_) {
- BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
+ for (IfacePtr iface : ifaces_) {
+ for (SocketInfo s : iface->getSockets()) {
if (FD_ISSET(s.sockfd_, &sockets)) {
receiveDHCP6Packet(s);
// Can take time so check one more time the watch socket.
return(enable_queue);
}
-
} // end of namespace isc::dhcp
} // end of namespace isc
#include <util/watched_thread.h>
#include <boost/function.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index_container.hpp>
#include <boost/noncopyable.hpp>
#include <boost/scoped_array.hpp>
#include <boost/shared_ptr.hpp>
namespace dhcp {
-
/// @brief IfaceMgr exception thrown thrown when interface detection fails.
class IfaceDetectError : public Exception {
public:
/// @brief Returns interface index.
///
/// @return interface index
- uint16_t getIndex() const { return ifindex_; }
+ uint32_t getIndex() const { return ifindex_; }
/// @brief Returns interface name.
///
std::vector<uint8_t> read_buffer_;
};
+/// @brief Type definition for the pointer to an @c Iface object.
typedef boost::shared_ptr<Iface> IfacePtr;
+/// @brief Collection of pointers to network interfaces.
+class IfaceCollection {
+public:
+
+ /// @brief Multi index container for network interfaces.
+ ///
+ /// This container allows to search for a network interfaces using
+ /// three indexes:
+ /// - sequenced: used to access elements in the order they have
+ /// been added to the container.
+ /// - interface index: used to access an interface using its index.
+ /// - interface name: used to access an interface using its name.
+ /// Note that indexes and names are unique.
+ typedef boost::multi_index_container<
+ // Container comprises elements of IfacePtr type.
+ IfacePtr,
+ // Here we start enumerating various indexes.
+ boost::multi_index::indexed_by<
+ // Sequenced index allows accessing elements in the same way
+ // as elements in std::list. Sequenced is the index #0.
+ boost::multi_index::sequenced<>,
+ // Start definition of index #1.
+ boost::multi_index::hashed_unique<
+ // Use the interface index as the key.
+ boost::multi_index::const_mem_fun<
+ Iface, uint32_t, &Iface::getIndex
+ >
+ >,
+ // Start definition of index #2.
+ boost::multi_index::hashed_unique<
+ // Use the interface name as the key.
+ boost::multi_index::const_mem_fun<
+ Iface, std::string, &Iface::getName
+ >
+ >
+ >
+ > IfaceContainer;
+
+ /// @brief Constructor.
+ IfaceCollection() { }
+
+ /// @brief Destructor.
+ ~IfaceCollection() { }
+
+ /// @brief Begin iterator.
+ ///
+ /// @return The container sequence begin iterator.
+ IfaceContainer::const_iterator begin() const {
+ return (ifaces_container_.begin());
+ }
+
+ /// @brief End iterator.
+ ///
+ /// @return The container sequence end iterator.
+ IfaceContainer::const_iterator end() const {
+ return (ifaces_container_.end());
+ }
+
+ /// @brief Empty predicate.
+ ///
+ /// @return If the container is empty true else false.
+ bool empty() const {
+ return (ifaces_container_.empty());
+ }
+
+ /// @brief Return the number of interfaces.
+ ///
+ /// @return The container size.
+ size_t size() const {
+ return (ifaces_container_.size());
+ }
+
+ /// @brief Clear the collection.
+ void clear() {
+ cache_.reset();
+ ifaces_container_.clear();
+ }
+
+ /// @brief Adds an interface to the collection.
+ ///
+ /// The interface is added at the end of sequence.
+ ///
+ /// @param iface reference to Iface object.
+ void push_back(const IfacePtr& iface) {
+ ifaces_container_.push_back(iface);
+ }
+
+ /// @brief Lookup by interface index.
+ ///
+ /// @param ifindex The index of the interface to find.
+ /// @return The interface with the index or null.
+ IfacePtr getIface(uint32_t ifindex);
+
+ /// @brief Lookup by interface name.
+ ///
+ /// @param ifname The name of the interface to find.
+ /// @return The interface with the name or null.
+ IfacePtr getIface(const std::string& ifname);
+
+private:
+ /// @brief Lookup by interface index.
+ ///
+ /// @param ifindex The index of the interface to find.
+ /// @param need_lock True when the cache operation needs to hold the mutex.
+ /// @return The interface with the index or null.
+ IfacePtr getIfaceInternal(uint32_t ifindex, bool need_lock);
+
+ /// @brief Lookup by interface name.
+ ///
+ /// The mutex must be held when called from a packet processing thread.
+ ///
+ /// @param ifname The name of the interface to find.
+ /// @param need_lock True when the cache operation needs to hold the mutex.
+ /// @return The interface with the name or null.
+ IfacePtr getIfaceInternal(const std::string& ifname, bool need_lock);
+
+ /// @brief The mutex for protecting the cache from concurrent
+ /// access from packet processing threads.
+ std::mutex mutex_;
+
+ /// @brief The last interface returned by a lookup method.
+ IfacePtr cache_;
+
+ /// @brief The container.
+ IfaceContainer ifaces_container_;
+};
+
/// @brief Forward declaration to the @c IfaceMgr.
class IfaceMgr;
// 2 maps (ifindex-indexed and name-indexed) and
// also hide it (make it public make tests easier for now)
- /// Type that holds a list of pointers to interfaces.
- typedef std::list<IfacePtr> IfaceCollection;
-
/// IfaceMgr is a singleton class. This method returns reference
/// to its sole instance.
///
// TODO: having 2 maps (ifindex->iface and ifname->iface would)
// probably be better for performance reasons
- /// List of available interfaces
+ /// @brief List of available interfaces
IfaceCollection ifaces_;
+ /// @brief Return an error when index search fails.
+ bool fail_on_index_not_found_;
+
// TODO: Also keep this interface on Iface once interface detection
// is implemented. We may need it e.g. to close all sockets on
// specific interface
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcp/tests/pkt_filter6_test_utils.h>
#include <dhcp/tests/packet_queue_testutils.h>
+#include <testutils/gtest_utils.h>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
const bool up, const bool running,
const bool inactive4,
const bool inactive6) {
- for (IfaceMgr::IfaceCollection::iterator iface = ifaces_.begin();
- iface != ifaces_.end(); ++iface) {
- if ((*iface)->getName() == name) {
- (*iface)->flag_loopback_ = loopback;
- (*iface)->flag_up_ = up;
- (*iface)->flag_running_ = running;
- (*iface)->inactive4_ = inactive4;
- (*iface)->inactive6_ = inactive6;
+ for (IfacePtr iface : ifaces_) {
+ if (iface->getName() == name) {
+ iface->flag_loopback_ = loopback;
+ iface->flag_up_ = up;
+ iface->flag_running_ = running;
+ iface->inactive4_ = inactive4;
+ iface->inactive6_ = inactive6;
}
}
}
EXPECT_NO_THROW(IfaceMgr::instance());
}
+// Basic tests for Iface inner class.
TEST_F(IfaceMgrTest, ifaceClass) {
- // Basic tests for Iface inner class
Iface iface("eth5", 7);
EXPECT_STREQ("eth5/7", iface.getFullName().c_str());
+
+ EXPECT_THROW_MSG(Iface("foo", -1), OutOfRange,
+ "Interface index must be in 0..2147483647");
+}
+
+// This test checks the getIface by packet method.
+TEST_F(IfaceMgrTest, getIfaceByPkt) {
+ NakedIfaceMgr ifacemgr;
+ // Create a set of fake interfaces. At the same time, remove the actual
+ // interfaces that have been detected by the IfaceMgr.
+ ifacemgr.createIfaces();
+
+ // Try IPv4 packet by name.
+ Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, 1234));
+ IfacePtr iface = ifacemgr.getIface(pkt4);
+ EXPECT_FALSE(iface);
+ pkt4->setIface("eth0");
+ iface = ifacemgr.getIface(pkt4);
+ EXPECT_TRUE(iface);
+ EXPECT_FALSE(pkt4->indexSet());
+
+ // Try IPv6 packet by index.
+ Pkt6Ptr pkt6(new Pkt6(DHCPV6_REPLY, 123456));
+ iface = ifacemgr.getIface(pkt6);
+ EXPECT_FALSE(iface);
+ ASSERT_TRUE(ifacemgr.getIface("eth0"));
+ pkt6->setIndex(ifacemgr.getIface("eth0")->getIndex() + 1);
+ iface = ifacemgr.getIface(pkt6);
+ ASSERT_TRUE(iface);
+
+ // Index has precedence when both name and index are available.
+ EXPECT_EQ("eth1", iface->getName());
+ pkt6->setIface("eth0");
+ iface = ifacemgr.getIface(pkt6);
+ ASSERT_TRUE(iface);
+ EXPECT_EQ("eth1", iface->getName());
+
+ // Not existing name fails.
+ pkt4->setIface("eth2");
+ iface = ifacemgr.getIface(pkt4);
+ EXPECT_FALSE(iface);
+
+ // Not existing index depends on fail_on_index_not_found_.
+ // Currently fail_on_index_not_found_ is false.
+ pkt6->setIndex(3);
+ iface = ifacemgr.getIface(pkt6);
+ ASSERT_TRUE(iface);
+ EXPECT_EQ("eth0", iface->getName());
+ EXPECT_EQ(1, iface->getIndex());
}
// Test that the IPv4 address can be retrieved for the interface.
EXPECT_FALSE(iface->hasAddress(IOAddress("2001:db8:1::2")));
}
+// This test checks it is not allowed to add duplicate interfaces.
+TEST_F(IfaceMgrTest, addInterface) {
+ IfaceMgrTestConfig config(true);
+
+ IfacePtr dup_name(new Iface("eth1", 123));
+ EXPECT_THROW_MSG(IfaceMgr::instance().addInterface(dup_name), Unexpected,
+ "Can't add eth1/123 when eth1/2 already exists.");
+ IfacePtr dup_index(new Iface("eth2", 2));
+ EXPECT_THROW_MSG(IfaceMgr::instance().addInterface(dup_index), Unexpected,
+ "Can't add eth2/2 when eth1/2 already exists.");
+
+ IfacePtr eth2(new Iface("eth2", 3));
+ EXPECT_NO_THROW(IfaceMgr::instance().addInterface(eth2));
+}
+
// TODO: Implement getPlainMac() test as soon as interface detection
// is implemented.
TEST_F(IfaceMgrTest, getIface) {
cout << "There are " << ifacemgr->getIfacesLst().size()
<< " interfaces." << endl;
- for (IfaceMgr::IfaceCollection::iterator iface=ifacemgr->getIfacesLst().begin();
- iface != ifacemgr->getIfacesLst().end();
- ++iface) {
- cout << " " << (*iface)->getFullName() << endl;
+ for (IfacePtr iface : ifacemgr->getIfacesLst()) {
+ cout << " " << iface->getFullName() << endl;
}
// Check that interface can be retrieved by ifindex