Commit 42ba6176 authored by Francis Dupont's avatar Francis Dupont
Browse files

[#553] Checkpoint: added IfaceCollection

parent a0a0a916
......@@ -368,8 +368,7 @@ public:
// deal with sockets here, just check if configuration handling
// is sane.
const IfaceMgr::IfaceCollection& ifaces =
IfaceMgr::instance().getIfaces();
const IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
// There must be some interface detected
if (ifaces.empty()) {
......
......@@ -837,8 +837,7 @@ NakedDhcpv6SrvTest::NakedDhcpv6SrvTest()
// it's ok if that fails. There should not be such a file anyway
static_cast<void>(remove(DUID_FILE));
const isc::dhcp::IfaceMgr::IfaceCollection& ifaces =
isc::dhcp::IfaceMgr::instance().getIfaces();
const IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
// There must be some interface detected
if (ifaces.empty()) {
......@@ -850,7 +849,7 @@ NakedDhcpv6SrvTest::NakedDhcpv6SrvTest()
valid_ifindex_ = (*ifaces.begin())->getIndex();
// Let's wipe all existing statistics.
isc::stats::StatsMgr::instance().removeAll();
StatsMgr::instance().removeAll();
}
NakedDhcpv6SrvTest::~NakedDhcpv6SrvTest() {
......
......@@ -12,9 +12,6 @@
#include <dhcp/iface_mgr.h>
#include <asiolink/io_address.h>
#include <boost/foreach.hpp>
using namespace isc::dhcp;
using namespace isc::asiolink;
......@@ -135,8 +132,8 @@ PerfSocket::~PerfSocket() {
void
PerfSocket::initSocketData() {
BOOST_FOREACH(IfacePtr iface, IfaceMgr::instance().getIfaces()) {
BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
for (IfacePtr iface : IfaceMgr::instance().getIfaces()) {
for (SocketInfo s : iface->getSockets()) {
if (s.sockfd_ == sockfd_) {
ifindex_ = iface->getIndex();
addr_ = s.addr_;
......@@ -151,13 +148,13 @@ Pkt4Ptr
PerfSocket::receive4(uint32_t timeout_sec, uint32_t timeout_usec) {
Pkt4Ptr pkt = IfaceMgr::instance().receive4(timeout_sec, timeout_usec);
if (pkt) {
try {
try {
pkt->unpack();
} catch (const std::exception &e) {
ExchangeStats::malformed_pkts_++;
std::cout << "Incorrect DHCP packet received"
<< e.what() << std::endl;
}
} catch (const std::exception &e) {
ExchangeStats::malformed_pkts_++;
std::cout << "Incorrect DHCP packet received"
<< e.what() << std::endl;
}
}
return (pkt);
}
......
......@@ -774,7 +774,7 @@ TEST_F(CommandOptionsTest, Interface) {
// here it is called by CommandOptions object internally
// so this function is covered by the test.
dhcp::IfaceMgr& iface_mgr = dhcp::IfaceMgr::instance();
const dhcp::IfaceMgr::IfaceCollection& ifaces = iface_mgr.getIfaces();
const dhcp::IfaceCollection& ifaces = iface_mgr.getIfaces();
std::string iface_name;
CommandOptions opt;
// The local loopback interface should be available.
......
......@@ -12,7 +12,6 @@
#include <util/io_utilities.h>
#include <util/range_utilities.h>
#include <util/strutil.h>
#include <boost/foreach.hpp>
#include <ctime>
#include <fstream>
#include <stdlib.h>
......@@ -244,10 +243,8 @@ DUIDFactory::createLL(const uint16_t htype,
void
DUIDFactory::createLinkLayerId(std::vector<uint8_t>& identifier,
uint16_t& htype) const {
const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
// Let's find suitable interface.
BOOST_FOREACH(IfacePtr iface, ifaces) {
for (IfacePtr iface : IfaceMgr::instance().getIfaces()) {
// All the following checks could be merged into one multi-condition
// statement, but let's keep them separated as perhaps one day
// we will grow knobs to selectively turn them on or off. Also,
......
This diff is collapsed.
......@@ -21,6 +21,10 @@
#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>
......@@ -33,7 +37,6 @@ namespace isc {
namespace dhcp {
/// @brief IfaceMgr exception thrown thrown when interface detection fails.
class IfaceDetectError : public Exception {
public:
......@@ -209,7 +212,7 @@ public:
/// @brief Returns interface index.
///
/// @return interface index
uint16_t getIndex() const { return ifindex_; }
uint32_t getIndex() const { return ifindex_; }
/// @brief Returns interface name.
///
......@@ -455,8 +458,136 @@ private:
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;
......@@ -507,9 +638,6 @@ public:
// 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.
///
......@@ -1264,9 +1392,12 @@ protected:
// 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
......
......@@ -15,6 +15,7 @@
#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>
......@@ -328,14 +329,13 @@ public:
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;
}
}
}
......@@ -921,11 +921,60 @@ TEST_F(IfaceMgrTest, instance) {
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.
......@@ -967,6 +1016,21 @@ TEST_F(IfaceMgrTest, ifaceHasAddress) {
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) {
......@@ -991,10 +1055,8 @@ 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
......
// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2020 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
......@@ -10,7 +10,6 @@
#include <dhcpsrv/cfg_iface.h>
#include <util/strutil.h>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <algorithm>
using namespace isc::asiolink;
......@@ -41,8 +40,7 @@ CfgIface::equals(const CfgIface& other) const {
bool
CfgIface::multipleAddressesPerInterfaceActive() const {
const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
BOOST_FOREACH(IfacePtr iface, ifaces) {
for (IfacePtr iface : IfaceMgr::instance().getIfaces()) {
if (iface->countActive4() > 1) {
return (true);
}
......@@ -172,7 +170,7 @@ CfgIface::openSockets(const uint16_t family, const uint16_t port,
// use_bcast is ignored for V6.
sopen = IfaceMgr::instance().openSockets6(port, error_callback);
}
if (!sopen) {
// If no socket were opened, log a warning because the server will
// not respond to any queries.
......@@ -191,8 +189,7 @@ CfgIface::reset() {
void
CfgIface::setState(const uint16_t family, const bool inactive,
const bool loopback_inactive) const {
const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
BOOST_FOREACH(IfacePtr iface, ifaces) {
for (IfacePtr iface : IfaceMgr::instance().getIfaces()) {
bool iface_inactive = iface->flag_loopback_ ? loopback_inactive : inactive;
if (family == AF_INET) {
iface->inactive4_ = iface_inactive;
......@@ -209,7 +206,7 @@ void
CfgIface::setIfaceAddrsState(const uint16_t family, const bool active,
Iface& iface) const {
// Activate/deactivate all addresses.
BOOST_FOREACH(Iface::Address addr, iface.getAddresses()) {
for (Iface::Address addr : iface.getAddresses()) {
if (addr.get().getFamily() == family) {
iface.setActive(addr.get(), active);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment