// Configuration may disable or enable interfaces so we have to
// reopen sockets according to new configuration.
- openActiveSockets(getPort(), useBroadcast());
+ CfgMgr::instance().getConfiguration()->iface_cfg_
+ .openSockets(getPort(), useBroadcast());
} catch (const std::exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(ex.what());
#include <dhcp4/dhcp4_log.h>
#include <hooks/hooks_manager.h>
#include <dhcp4/json_config_parser.h>
+#include <dhcpsrv/cfgmgr.h>
using namespace isc::data;
using namespace isc::hooks;
err << "Server object not initialized, can't process config.";
return (isc::config::createAnswer(1, err.str()));
}
-
+
ConstElementPtr answer = configureDhcp4Server(*srv, config);
// safe and we really don't want to emit exceptions to whoever called this
// method. Instead, catch an exception and create appropriate answer.
try {
- srv->openActiveSockets(srv->getPort(), getInstance()->useBroadcast());
+ CfgMgr::instance().getConfiguration()->iface_cfg_
+ .openSockets(srv->getPort(), getInstance()->useBroadcast());
+
} catch (std::exception& ex) {
err << "failed to open sockets after server reconfiguration: "
<< ex.what();
}
}
-void
-Dhcpv4Srv::openActiveSockets(const uint16_t port,
- const bool use_bcast) {
- IfaceMgr::instance().closeSockets();
-
- // Get the reference to the collection of interfaces. This reference should
- // be valid as long as the program is run because IfaceMgr is a singleton.
- // Therefore we can safely iterate over instances of all interfaces and
- // modify their flags. Here we modify flags which indicate whether socket
- // should be open for a particular interface or not.
- const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
- for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
- iface != ifaces.end(); ++iface) {
- Iface* iface_ptr = IfaceMgr::instance().getIface(iface->getName());
- if (iface_ptr == NULL) {
- isc_throw(isc::Unexpected, "Interface Manager returned NULL"
- << " instance of the interface when DHCPv4 server was"
- << " trying to reopen sockets after reconfiguration");
- }
- // Ignore loopback interfaces.
- if (iface_ptr->flag_loopback_) {
- iface_ptr->inactive4_ = true;
-
- } else if (CfgMgr::instance().isActiveIface(iface->getName())) {
- iface_ptr->inactive4_ = false;
- LOG_INFO(dhcp4_logger, DHCP4_ACTIVATE_INTERFACE)
- .arg(iface->getFullName());
-
- } else {
- // For deactivating interface, it should be sufficient to log it
- // on the debug level because it is more useful to know what
- // interface is activated which is logged on the info level.
- LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC,
- DHCP4_DEACTIVATE_INTERFACE).arg(iface->getName());
- iface_ptr->inactive4_ = true;
-
- }
- }
- // Let's reopen active sockets. openSockets4 will check internally whether
- // sockets are marked active or inactive.
- /// @todo Optimization: we should not reopen all sockets but rather select
- /// those that have been affected by the new configuration.
- isc::dhcp::IfaceMgrErrorMsgCallback error_handler =
- boost::bind(&Dhcpv4Srv::ifaceMgrSocket4ErrorHandler, _1);
- if (!IfaceMgr::instance().openSockets4(port, use_bcast, error_handler)) {
- LOG_WARN(dhcp4_logger, DHCP4_NO_SOCKETS_OPEN);
- }
-}
-
size_t
Dhcpv4Srv::unpackOptions(const OptionBuffer& buf,
const std::string& option_space,
///
/// @name Public accessors returning values required to (re)open sockets.
///
- /// These accessors must be public because sockets are reopened from the
- /// static configuration callback handler. This callback handler invokes
- /// @c ControlledDhcpv4Srv::openActiveSockets which requires parameters
- /// which has to be retrieved from the @c ControlledDhcpv4Srv object.
- /// They are retrieved using these public functions
//@{
///
/// @brief Get UDP port on which server should listen.
}
//@}
- /// @brief Open sockets which are marked as active in @c CfgMgr.
- ///
- /// This function reopens sockets according to the current settings in the
- /// Configuration Manager. It holds the list of the interfaces which server
- /// should listen on. This function will open sockets on these interfaces
- /// only. This function is not exception safe.
- ///
- /// @param port UDP port on which server should listen.
- /// @param use_bcast should broadcast flags be set on the sockets.
- static void openActiveSockets(const uint16_t port, const bool use_bcast);
-
/// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled.
///
/// If updates are enabled, it Instructs the D2ClientMgr singleton to
#include <dhcp/option_int.h>
#include <dhcp/docsis3_option_defs.h>
#include <dhcp/classify.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/testutils/config_result_check.h>
// deal with sockets here, just check if configuration handling
// is sane.
srv_.reset(new Dhcpv4Srv(0));
- CfgMgr::instance().deleteActiveIfaces();
// Create fresh context.
globalContext()->copyContext(ParserContext(Option::V4));
}
// This test verifies that it is possible to select subset of interfaces
// on which server should listen.
TEST_F(Dhcp4ParserTest, selectedInterfaces) {
+ IfaceMgrTestConfig test_config(true);
+
ConstElementPtr x;
string config = "{ \"interfaces\": [ \"eth0\", \"eth1\" ],"
"\"rebind-timer\": 2000, "
// Make sure the config manager is clean and there is no hanging
// interface configuration.
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth0"));
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth1"));
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
+ EXPECT_FALSE(test_config.socketOpen("eth0", AF_INET));
+ EXPECT_FALSE(test_config.socketOpen("eth1", AF_INET));
// Apply configuration.
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
ASSERT_TRUE(status);
checkResult(status, 0);
+ CfgMgr::instance().getConfiguration()->iface_cfg_.openSockets(10000);
+
// eth0 and eth1 were explicitly selected. eth2 was not.
- EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth0"));
- EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth1"));
- EXPECT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
+ EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
+ EXPECT_TRUE(test_config.socketOpen("eth1", AF_INET));
}
// This test verifies that it is possible to configure the server in such a way
// that it listens on all interfaces.
TEST_F(Dhcp4ParserTest, allInterfaces) {
+ IfaceMgrTestConfig test_config(true);
+
ConstElementPtr x;
// This configuration specifies two interfaces on which server should listen
// but it also includes asterisk. The asterisk switches server into the
ConstElementPtr status;
// Make sure there is no old configuration.
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth0"));
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth1"));
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
+ ASSERT_FALSE(test_config.socketOpen("eth0", AF_INET));
+ ASSERT_FALSE(test_config.socketOpen("eth1", AF_INET));
// Apply configuration.
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
ASSERT_TRUE(status);
checkResult(status, 0);
+ CfgMgr::instance().getConfiguration()->iface_cfg_.openSockets(10000);
+
// All interfaces should be now active.
- EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth0"));
- EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth1"));
- EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth2"));
+ ASSERT_TRUE(test_config.socketOpen("eth0", AF_INET));
+ ASSERT_TRUE(test_config.socketOpen("eth1", AF_INET));
}
// This test checks the ability of the server to parse a configuration
ASSERT_NO_THROW(naked_srv.reset(new NakedDhcpv4Srv(0)));
}
-// This test verifies that exception is not thrown when an error occurs during
-// opening sockets. This test forces an error by adding a fictious interface
-// to the IfaceMgr. An attempt to open socket on this interface must always
-// fail. The DHCPv4 installs the error handler function to prevent exceptions
-// being thrown from the openSockets4 function.
-// @todo The server tests for socket should be extended but currently the
-// ability to unit test the sockets code is somewhat limited.
-TEST_F(Dhcpv4SrvTest, openActiveSockets) {
- ASSERT_NO_THROW(CfgMgr::instance().activateAllIfaces());
-
- Iface iface("bogusiface", 255);
- iface.flag_loopback_ = false;
- iface.flag_up_ = true;
- iface.flag_running_ = true;
- iface.inactive4_ = false;
- iface.addAddress(IOAddress("192.0.0.0"));
- IfaceMgr::instance().addInterface(iface);
- ASSERT_NO_THROW(Dhcpv4Srv::openActiveSockets(DHCP4_SERVER_PORT, false));
-}
-
// Verifies that DISCOVER message can be processed correctly,
// that the OFFER message generated in response is valid and
// contains necessary options.
NakedDhcpv4Srv srv(0);
ConstElementPtr x;
- string config = "{ \"interfaces\": [ \"all\" ],"
+ string config = "{ \"interfaces\": [ \"*\" ],"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
" \"option-data\": [ {"
// src/lib/dhcp/docsis3_option_defs.h.
TEST_F(Dhcpv4SrvTest, vendorOptionsDocsisDefinitions) {
ConstElementPtr x;
- string config_prefix = "{ \"interfaces\": [ \"all\" ],"
+ string config_prefix = "{ \"interfaces\": [ \"*\" ],"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
" \"option-data\": [ {"
pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110")));
subnet_->addPool(pool_);
- CfgMgr::instance().deleteActiveIfaces();
+ CfgMgr::instance().getConfiguration()->iface_cfg_.reset();
CfgMgr::instance().deleteSubnets4();
CfgMgr::instance().addSubnet4(subnet_);
Dhcpv4SrvTest::~Dhcpv4SrvTest() {
// Make sure that we revert to default value
+ CfgMgr::instance().getConfiguration()->iface_cfg_.reset();
CfgMgr::instance().echoClientId(true);
}
/// - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
const char* DORA_CONFIGS[] = {
// Configuration 0
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"valid-lifetime\": 600,"
"\"subnet4\": [ { "
" \"subnet\": \"10.0.0.0/24\", "
"}",
// Configuration 1
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"valid-lifetime\": 600,"
"\"subnet4\": [ { "
" \"subnet\": \"192.0.2.0/24\", "
/// - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
const char* INFORM_CONFIGS[] = {
// Configuration 0
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"valid-lifetime\": 600,"
"\"subnet4\": [ { "
" \"subnet\": \"10.0.0.0/24\", "
"}",
// Configuration 1
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"valid-lifetime\": 600,"
"\"subnet4\": [ { "
" \"subnet\": \"192.0.2.0/24\", "
#include <config.h>
#include <cc/data.h>
+#include <dhcpsrv/cfgmgr.h>
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6_log.h>
#include <hooks/hooks_manager.h>
// safe and we really don't want to emit exceptions to the callback caller.
// Instead, catch an exception and create appropriate answer.
try {
- srv->openActiveSockets(srv->getPort());
+ CfgMgr::instance().getConfiguration()->iface_cfg_
+ .openSockets(srv->getPort());
+
} catch (const std::exception& ex) {
std::ostringstream err;
- err << "failed to open sockets after server reconfiguration: " << ex.what();
+ err << "failed to open sockets after server reconfiguration: "
+ << ex.what();
answer = isc::config::createAnswer(1, err.str());
}
// Instantiate allocation engine
alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
+ // We have to point out to the CfgMgr that the we are in the IPv6
+ // domain, so as the IPv6 sockets are opened rather than IPv4 sockets
+ // which are the default.
+ CfgMgr::instance().getConfiguration()
+ ->iface_cfg_.setFamily(IfaceCfg::V6);
+
/// @todo call loadLibraries() when handling configuration changes
} catch (const std::exception &e) {
return reply;
}
-void
-Dhcpv6Srv::openActiveSockets(const uint16_t port) {
- IfaceMgr::instance().closeSockets();
-
- // Get the reference to the collection of interfaces. This reference should be
- // valid as long as the program is run because IfaceMgr is a singleton.
- // Therefore we can safely iterate over instances of all interfaces and modify
- // their flags. Here we modify flags which indicate wheter socket should be
- // open for a particular interface or not.
- const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
- for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
- iface != ifaces.end(); ++iface) {
- Iface* iface_ptr = IfaceMgr::instance().getIface(iface->getName());
- if (iface_ptr == NULL) {
- isc_throw(isc::Unexpected, "Interface Manager returned NULL"
- << " instance of the interface when DHCPv6 server was"
- << " trying to reopen sockets after reconfiguration");
- }
-
- // Ignore loopback interfaces.
- if (iface_ptr->flag_loopback_) {
- iface_ptr->inactive6_ = true;
-
- } else if (CfgMgr::instance().isActiveIface(iface->getName())) {
- iface_ptr->inactive6_ = false;
- LOG_INFO(dhcp6_logger, DHCP6_ACTIVATE_INTERFACE)
- .arg(iface->getFullName());
-
- } else {
- // For deactivating interface, it should be sufficient to log it
- // on the debug level because it is more useful to know what
- // interface is activated which is logged on the info level.
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC,
- DHCP6_DEACTIVATE_INTERFACE).arg(iface->getName());
- iface_ptr->inactive6_ = true;
-
- }
-
- iface_ptr->clearUnicasts();
-
- const IOAddress* unicast = CfgMgr::instance().getUnicast(iface->getName());
- if (unicast) {
- LOG_INFO(dhcp6_logger, DHCP6_SOCKET_UNICAST).arg(unicast->toText())
- .arg(iface->getName());
- iface_ptr->addUnicast(*unicast);
- }
- }
- // Let's reopen active sockets. openSockets6 will check internally whether
- // sockets are marked active or inactive.
- // @todo Optimization: we should not reopen all sockets but rather select
- // those that have been affected by the new configuration.
- isc::dhcp::IfaceMgrErrorMsgCallback error_handler =
- boost::bind(&Dhcpv6Srv::ifaceMgrSocket6ErrorHandler, _1);
- if (!IfaceMgr::instance().openSockets6(port, error_handler)) {
- LOG_WARN(dhcp6_logger, DHCP6_NO_SOCKETS_OPEN);
- }
-}
-
size_t
Dhcpv6Srv::unpackOptions(const OptionBuffer& buf,
const std::string& option_space,
/// Typically, server listens on UDP port 547. Other ports are only
/// used for testing purposes.
///
- /// This accessor must be public because sockets are reopened from the
- /// static configuration callback handler. This callback handler invokes
- /// @c ControlledDhcpv4Srv::openActiveSockets which requires port parameter
- /// which has to be retrieved from the @c ControlledDhcpv4Srv object.
- /// They are retrieved using this public function.
- ///
/// @return UDP port on which server should listen.
uint16_t getPort() const {
return (port_);
}
- /// @brief Open sockets which are marked as active in @c CfgMgr.
- ///
- /// This function reopens sockets according to the current settings in the
- /// Configuration Manager. It holds the list of the interfaces which server
- /// should listen on. This function will open sockets on these interfaces
- /// only. This function is not exception safe.
- ///
- /// @param port UDP port on which server should listen.
- static void openActiveSockets(const uint16_t port);
-
/// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled.
///
/// If updates are enabled, it Instructs the D2ClientMgr singleton to
#include <dhcp/iface_mgr.h>
#include <dhcp/option_custom.h>
#include <dhcp/option_int.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcp6/json_config_parser.h>
#include <dhcp6/dhcp6_srv.h>
#include <dhcpsrv/addr_utilities.h>
// deal with sockets here, just check if configuration handling
// is sane.
- const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
+ const IfaceMgr::IfaceCollection& ifaces =
+ IfaceMgr::instance().getIfaces();
// There must be some interface detected
if (ifaces.empty()) {
/// test to make sure that contents of the database do not affect the
/// results of subsequent tests.
void resetConfiguration() {
- string config = "{ \"interfaces\": [ \"all\" ],"
+ string config = "{ \"interfaces\": [ \"*\" ],"
"\"hooks-libraries\": [ ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
// properly test interface configuration we disable listening on
// all interfaces before each test and later check that this setting
// has been overriden by the configuration used in the test.
- CfgMgr::instance().deleteActiveIfaces();
+ CfgMgr::instance().getConfiguration()->iface_cfg_.reset();
+ CfgMgr::instance().getConfiguration()->
+ iface_cfg_.setFamily(IfaceCfg::V6);
// Create fresh context.
globalContext()->copyContext(ParserContext(Option::V6));
}
// Create the first part of the configuration string.
string config =
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"hooks-libraries\": [";
// Append the libraries (separated by commas if needed)
// This test verifies that it is possible to select subset of interfaces on
// which server should listen.
TEST_F(Dhcp6ParserTest, selectedInterfaces) {
+ IfaceMgrTestConfig test_config(true);
// Make sure there is no garbage interface configuration in the CfgMgr.
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth0"));
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth1"));
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
+ ASSERT_FALSE(test_config.socketOpen("eth0", AF_INET6));
+ ASSERT_FALSE(test_config.socketOpen("eth1", AF_INET6));
ConstElementPtr status;
- string config = "{ \"interfaces\": [ \"eth0\", \"eth1\" ],"
+ string config = "{ \"interfaces\": [ \"eth0\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
// as the pool does not belong to that subnet
checkResult(status, 0);
+ CfgMgr::instance().getConfiguration()->iface_cfg_.openSockets(10000);
+
// eth0 and eth1 were explicitly selected. eth2 was not.
- EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth0"));
- EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth1"));
- EXPECT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
+ EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET6));
+ EXPECT_FALSE(test_config.socketOpen("eth1", AF_INET6));
}
// This test verifies that it is possible to configure the server to listen on
// all interfaces.
TEST_F(Dhcp6ParserTest, allInterfaces) {
+ IfaceMgrTestConfig test_config(true);
- // Make sure there is no garbage interface configuration in the CfgMgr.
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth0"));
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth1"));
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
+ ASSERT_FALSE(test_config.socketOpen("eth0", AF_INET6));
+ ASSERT_FALSE(test_config.socketOpen("eth1", AF_INET6));
ConstElementPtr status;
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
-
- // returned value must be 1 (values error)
- // as the pool does not belong to that subnet
checkResult(status, 0);
+ CfgMgr::instance().getConfiguration()->iface_cfg_.openSockets(10000);
+
// All interfaces should be now active.
- EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth0"));
- EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth1"));
- EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth2"));
+ EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET6));
+ EXPECT_TRUE(test_config.socketOpen("eth1", AF_INET6));
}
///
const char* CONFIRM_CONFIGS[] = {
// Configuration 0
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000 }",
// Configuration 1
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
void
Dhcp6SrvD2Test::reset() {
- std::string config = "{ \"interfaces\": [ \"all\" ],"
+ std::string config = "{ \"interfaces\": [ \"*\" ],"
"\"hooks-libraries\": [ ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
IfaceMgrTestConfig test_config(true);
ConstElementPtr x;
- string config = "{ \"interfaces\": [ \"all\" ],"
+ string config = "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
IfaceMgrTestConfig test_config(true);
- string config = "{ \"interfaces\": [ \"all\" ],"
+ string config = "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
// src/lib/dhcp/docsis3_option_defs.h.
TEST_F(Dhcpv6SrvTest, vendorOptionsDocsisDefinitions) {
ConstElementPtr x;
- string config_prefix = "{ \"interfaces\": [ \"all\" ],"
+ string config_prefix = "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
/// - this specific configuration is used by tests which don't use relays
const char* REBIND_CONFIGS[] = {
// Configuration 0
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000 }",
// Configuration 1
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000 }",
// Configuration 2
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000 }",
// Configuration 3
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000 }",
// Configuration 4
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000 }",
// Configuration 5
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
/// - prefixes of length 64, delegated from the pool: 2001:db8:3::/48
const char* CONFIGS[] = {
// Configuration 0
- "{ \"interfaces\": [ \"all\" ],"
+ "{ \"interfaces\": [ \"*\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
iface->inactive6_ = inactive6.flag_;
}
+bool
+IfaceMgrTestConfig::socketOpen(const std::string& iface_name,
+ const int family) const {
+ Iface* iface = IfaceMgr::instance().getIface(iface_name);
+ if (iface == NULL) {
+ isc_throw(Unexpected, "No such interface '" << iface_name << "'");
+ }
+
+ const Iface::SocketCollection& sockets = iface->getSockets();
+ for (Iface::SocketCollection::const_iterator sock = sockets.begin();
+ sock != sockets.end(); ++sock) {
+ if (sock->family_ == family) {
+ return (true);
+ }
+ }
+ return (false);
+}
+
+bool
+IfaceMgrTestConfig::unicastOpen(const std::string& iface_name) const {
+ Iface* iface = IfaceMgr::instance().getIface(iface_name);
+ if (iface == NULL) {
+ isc_throw(Unexpected, "No such interface '" << iface_name << "'");
+ }
+
+ const Iface::SocketCollection& sockets = iface->getSockets();
+ for (Iface::SocketCollection::const_iterator sock = sockets.begin();
+ sock != sockets.end(); ++sock) {
+ if ((!sock->addr_.isV6LinkLocal()) &&
+ (!sock->addr_.isV6Multicast())) {
+ return (true);
+ }
+ }
+ return (false);
+}
+
}
}
}
const FlagInactive4& inactive4,
const FlagInactive6& inactive6);
+ /// @brief Checks if socket of the specified family is opened on interface.
+ ///
+ /// @param iface_name Interface name.
+ /// @param family One of: AF_INET or AF_INET6
+ bool socketOpen(const std::string& iface_name, const int family) const;
+
+ /// @brief Checks if unicast socket is opened on interface.
+ ///
+ /// @param iface_name Interface name.
+ bool unicastOpen(const std::string& iface_name) const;
+
+
private:
/// @brief Currently used packet filter for DHCPv4.
PktFilterPtr packet_filter4_;
return (datadir_);
}
-void
-CfgMgr::addActiveIface(const std::string& iface) {
-
- size_t pos = iface.find("/");
- std::string iface_copy = iface;
-
- if (pos != std::string::npos) {
- std::string addr_string = iface.substr(pos + 1);
- try {
- IOAddress addr(addr_string);
- iface_copy = iface.substr(0,pos);
- unicast_addrs_.insert(make_pair(iface_copy, addr));
- } catch (...) {
- isc_throw(BadValue, "Can't convert '" << addr_string
- << "' into address in interface defition ('"
- << iface << "')");
- }
- }
-
- if (isIfaceListedActive(iface_copy)) {
- isc_throw(DuplicateListeningIface,
- "attempt to add duplicate interface '" << iface_copy << "'"
- " to the set of interfaces on which server listens");
- }
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_IFACE)
- .arg(iface_copy);
- active_ifaces_.push_back(iface_copy);
-}
-
-void
-CfgMgr::activateAllIfaces() {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
- DHCPSRV_CFGMGR_ALL_IFACES_ACTIVE);
- all_ifaces_active_ = true;
-}
-
-void
-CfgMgr::deleteActiveIfaces() {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
- DHCPSRV_CFGMGR_CLEAR_ACTIVE_IFACES);
- active_ifaces_.clear();
- all_ifaces_active_ = false;
-
- unicast_addrs_.clear();
-}
-
-bool
-CfgMgr::isActiveIface(const std::string& iface) const {
-
- // @todo Verify that the interface with the specified name is
- // present in the system.
-
- // If all interfaces are marked active, there is no need to check that
- // the name of this interface has been explicitly listed.
- if (all_ifaces_active_) {
- return (true);
- }
- return (isIfaceListedActive(iface));
-}
-
-bool
-CfgMgr::isIfaceListedActive(const std::string& iface) const {
- for (ActiveIfacesCollection::const_iterator it = active_ifaces_.begin();
- it != active_ifaces_.end(); ++it) {
- if (iface == *it) {
- return (true);
- }
- }
- return (false);
-}
-
bool
CfgMgr::isDuplicate(const Subnet4& subnet) const {
for (Subnet4Collection::const_iterator subnet_it = subnets4_.begin();
}
-const isc::asiolink::IOAddress*
-CfgMgr::getUnicast(const std::string& iface) const {
- UnicastIfacesCollection::const_iterator addr = unicast_addrs_.find(iface);
- if (addr == unicast_addrs_.end()) {
- return (NULL);
- }
- return (&(*addr).second);
-}
-
void
CfgMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
d2_client_mgr_.setD2ClientConfig(new_config);
}
CfgMgr::CfgMgr()
- : datadir_(DHCP_DATA_DIR),
- all_ifaces_active_(false), echo_v4_client_id_(true),
+ : datadir_(DHCP_DATA_DIR), echo_v4_client_id_(true),
d2_client_mgr_(), configuration_(new Configuration()) {
// DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
// Note: the definition of DHCP_DATA_DIR needs to include quotation marks
/// @return data directory
std::string getDataDir();
- /// @brief Adds the name of the interface to the set of interfaces on which
- /// server should listen.
- ///
- /// @param iface A name of the interface being added to the listening set.
- void addActiveIface(const std::string& iface);
-
- /// @brief Sets the flag which indicates that server is supposed to listen
- /// on all available interfaces.
- ///
- /// This function does not close or open sockets. It simply marks that
- /// server should start to listen on all interfaces the next time sockets
- /// are reopened. Server should examine this flag when it gets reconfigured
- /// and configuration changes the interfaces that server should listen on.
- void activateAllIfaces();
-
- /// @brief Clear the collection of the interfaces that server should listen
- /// on.
- ///
- /// Apart from clearing the list of interfaces specified with
- /// @c CfgMgr::addListeningInterface, it also disables listening on all
- /// interfaces if it has been enabled using
- /// @c CfgMgr::activateAllInterfaces.
- /// Likewise @c CfgMgr::activateAllIfaces, this function does not close or
- /// open sockets. It marks all interfaces inactive for DHCP traffic.
- /// Server should examine this new setting when it attempts to
- /// reopen sockets (as a result of reconfiguration).
- void deleteActiveIfaces();
-
- /// @brief Check if specified interface should be used to listen to DHCP
- /// traffic.
- ///
- /// @param iface A name of the interface to be checked.
- ///
- /// @return true if the specified interface belongs to the set of the
- /// interfaces on which server is configured to listen.
- bool isActiveIface(const std::string& iface) const;
-
- /// @brief returns unicast a given interface should listen on (or NULL)
- ///
- /// This method will return an address for a specified interface, if the
- /// server is supposed to listen on unicast address. This address is
- /// intended to be used immediately. This pointer is valid only until
- /// the next configuration change.
- ///
- /// @return IOAddress pointer (or NULL if none)
- const isc::asiolink::IOAddress*
- getUnicast(const std::string& iface) const;
-
/// @brief Sets whether server should send back client-id in DHCPv4
///
/// This is a compatibility flag. The default (true) is compliant with
private:
- /// @brief Checks if the specified interface is listed as active.
- ///
- /// This function searches for the specified interface name on the list of
- /// active interfaces: @c CfgMgr::active_ifaces_. It does not take into
- /// account @c CfgMgr::all_ifaces_active_ flag. If this flag is set to true
- /// but the specified interface does not belong to
- /// @c CfgMgr::active_ifaces_, it will return false.
- ///
- /// @param iface interface name.
- ///
- /// @return true if specified interface belongs to
- /// @c CfgMgr::active_ifaces_.
- bool isIfaceListedActive(const std::string& iface) const;
-
/// @brief Checks that the IPv4 subnet with the given id already exists.
///
/// @param subnet Subnet for which this function will check if the other
/// @brief directory where data files (e.g. server-id) are stored
std::string datadir_;
- /// @name A collection of interface names on which server listens.
- //@{
- typedef std::list<std::string> ActiveIfacesCollection;
- std::list<std::string> active_ifaces_;
- //@}
-
- /// @name a collection of unicast addresses and the interfaces names the
- // server is supposed to listen on
- //@{
- typedef std::map<std::string, isc::asiolink::IOAddress> UnicastIfacesCollection;
- UnicastIfacesCollection unicast_addrs_;
-
- /// A flag which indicates that server should listen on all available
- /// interfaces.
- bool all_ifaces_active_;
-
/// Indicates whether v4 server should send back client-id
bool echo_v4_client_id_;
#ifndef DHCPSRV_CONFIGURATION_H
#define DHCPSRV_CONFIGURATION_H
+#include <dhcpsrv/iface_cfg.h>
#include <log/logger_level.h>
#include <boost/shared_ptr.hpp>
#include <vector>
/// @brief logging specific information
LoggingInfoStorage logging_info_;
+
+ /// @brief Interface configuration.
+ ///
+ /// Used to select interfaces on which the DHCP server will listen to
+ /// queries.
+ IfaceCfg iface_cfg_;
+
};
/// @brief pointer to the configuration
namespace isc {
namespace dhcp {
-namespace {
-const char* ALL_IFACES_KEYWORD = "*";
-}
-
// *********************** ParserContext *************************
ParserContext::ParserContext(Option::Universe universe):
void
InterfaceListConfigParser::build(ConstElementPtr value) {
- // First, we iterate over all specified entries and add it to the
- // local container so as we can do some basic validation, e.g. eliminate
- // duplicates.
+ ConfigurationPtr config = CfgMgr::instance().getConfiguration();
+ config->iface_cfg_.reset();
BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
std::string iface_name = iface->stringValue();
- if (iface_name != ALL_IFACES_KEYWORD) {
- // Let's eliminate duplicates. We could possibly allow duplicates,
- // but if someone specified duplicated interface name it is likely
- // that he mistyped the configuration. Failing here should draw his
- // attention.
- if (isIfaceAdded(iface_name)) {
- isc_throw(isc::dhcp::DhcpConfigError, "duplicate interface"
- << " name '" << iface_name << "' specified in '"
- << param_name_ << "' configuration parameter "
- "(" << value->getPosition() << ")");
- }
- // @todo check that this interface exists in the system!
- // The IfaceMgr exposes mechanisms to check this.
-
- // Add the interface name if ok.
- interfaces_.push_back(iface_name);
-
- } else {
- activate_all_ = true;
+ try {
+ config->iface_cfg_.use(iface_name);
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError, "Failed to select interface: "
+ << ex.what() << " (" << value->getPosition() << ")");
}
}
}
void
InterfaceListConfigParser::commit() {
- CfgMgr& cfg_mgr = CfgMgr::instance();
- // Remove active interfaces and clear a flag which marks all interfaces
- // active
- cfg_mgr.deleteActiveIfaces();
-
- if (activate_all_) {
- // Activate all interfaces. There is not need to add their names
- // explicitly.
- cfg_mgr.activateAllIfaces();
-
- } else {
- // Explicitly add names of the interfaces which server should listen on.
- BOOST_FOREACH(std::string iface, interfaces_) {
- cfg_mgr.addActiveIface(iface);
- }
- }
+ // Do nothing. CfgMgr has been updated during build.
}
bool
/// @param value pointer to the content of parsed values
virtual void build(isc::data::ConstElementPtr value);
- /// @brief commits interfaces list configuration
+ /// @brief Does nothing.
virtual void commit();
private:
to clients that are no longer active on the network will become available
available sooner.
-% DHCPSRV_CFGMGR_ADD_IFACE adding listening interface %1
+% DHCPSRV_CFGMGR_ADD_IFACE listening on interface %1
A debug message issued when new interface is being added to the collection of
interfaces on which server listens to DHCP messages.
+% DHCPSRV_CFGMGR_ADD_UNICAST listening on unicast address %1 on interface %2
+A debug message issued when new configuring DHCP server to listen on unicast
+address on the specific interface.
+
% DHCPSRV_CFGMGR_ADD_SUBNET4 adding subnet %1
A debug message reported when the DHCP configuration manager is adding the
specified IPv4 subnet to its database.
}
}
+ // Before opening any sockets, close existing ones.
+ closeSockets();
+
// Set the callback which is called when the socket fails to open
// for some specific interface. This callback will simply log a
// warning message.
<< "' doesn't exist in the system");
}
- std::pair<IfaceSet::iterator, bool> res = iface_set_.insert(name);
- if (!res.second) {
+ // If interface has already been specified.
+ if (iface_set_.find(name) != iface_set_.end()) {
isc_throw(DuplicateIfaceName, "interface '" << name
<< "' has already been specified");
+
}
+ // All ok, add interface.
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
+ DHCPSRV_CFGMGR_ADD_IFACE)
+ .arg(name);
+ iface_set_.insert(name);
+
} else if (wildcard_used_) {
isc_throw(DuplicateIfaceName, "the wildcard interface '"
<< ALL_IFACES_KEYWORD << "' can only be specified once");
} else {
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
+ DHCPSRV_CFGMGR_ALL_IFACES_ACTIVE);
wildcard_used_ = true;
}
// Insert address and the interface to the collection of unicast
// addresses.
- std::pair<UnicastMap::iterator, bool> res =
- unicast_map_.insert(std::pair<std::string, IOAddress>(name, addr));
-
- // If some other unicast address has been added for the interface
- // return an error. The new address didn't override the existing one.
- if (!res.second) {
+ if (unicast_map_.find(name) != unicast_map_.end()) {
isc_throw(DuplicateIfaceName, "must not specify unicast address '"
<< addr << "' for interface '" << name << "' "
"because other unicast address has already been"
" specified for this interface");
}
-
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_UNICAST)
+ .arg(addr.toText()).arg(name);
+ unicast_map_.insert(std::pair<std::string, IOAddress>(name, addr));
}
}
CfgMgr::instance().deleteSubnets4();
CfgMgr::instance().deleteSubnets6();
CfgMgr::instance().deleteOptionDefs();
- CfgMgr::instance().deleteActiveIfaces();
}
/// @brief generates interface-id option based on provided text
/// @todo decide if a duplicate vendor space is allowed.
}
-// This test verifies that it is possible to specify interfaces that server
-// should listen on.
-TEST_F(CfgMgrTest, addActiveIface) {
- CfgMgr& cfg_mgr = CfgMgr::instance();
-
- EXPECT_NO_THROW(cfg_mgr.addActiveIface("eth0"));
- EXPECT_NO_THROW(cfg_mgr.addActiveIface("eth1"));
-
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth0"));
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth1"));
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth2"));
-
- EXPECT_NO_THROW(cfg_mgr.deleteActiveIfaces());
-
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth0"));
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth1"));
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth2"));
-}
-
-
-// This test verifies that it is possible to specify interfaces that server
-// should listen on.
-TEST_F(CfgMgrTest, addUnicastAddresses) {
- CfgMgr& cfg_mgr = CfgMgr::instance();
-
- EXPECT_NO_THROW(cfg_mgr.addActiveIface("eth1/2001:db8::1"));
- EXPECT_NO_THROW(cfg_mgr.addActiveIface("eth2/2001:db8::2"));
- EXPECT_NO_THROW(cfg_mgr.addActiveIface("eth3"));
-
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth1"));
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth2"));
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth3"));
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth4"));
-
- ASSERT_TRUE(cfg_mgr.getUnicast("eth1"));
- EXPECT_EQ("2001:db8::1", cfg_mgr.getUnicast("eth1")->toText());
- EXPECT_EQ("2001:db8::2", cfg_mgr.getUnicast("eth2")->toText());
- EXPECT_FALSE(cfg_mgr.getUnicast("eth3"));
- EXPECT_FALSE(cfg_mgr.getUnicast("eth4"));
-
- EXPECT_NO_THROW(cfg_mgr.deleteActiveIfaces());
-
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth1"));
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth2"));
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth3"));
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth4"));
-
- ASSERT_FALSE(cfg_mgr.getUnicast("eth1"));
- ASSERT_FALSE(cfg_mgr.getUnicast("eth2"));
- EXPECT_FALSE(cfg_mgr.getUnicast("eth3"));
- EXPECT_FALSE(cfg_mgr.getUnicast("eth4"));
-}
-
-
-// This test verifies that it is possible to set the flag which configures the
-// server to listen on all interfaces.
-TEST_F(CfgMgrTest, activateAllIfaces) {
- CfgMgr& cfg_mgr = CfgMgr::instance();
-
- cfg_mgr.addActiveIface("eth0");
- cfg_mgr.addActiveIface("eth1");
-
- ASSERT_TRUE(cfg_mgr.isActiveIface("eth0"));
- ASSERT_TRUE(cfg_mgr.isActiveIface("eth1"));
- ASSERT_FALSE(cfg_mgr.isActiveIface("eth2"));
-
- cfg_mgr.activateAllIfaces();
-
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth0"));
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth1"));
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth2"));
-
- cfg_mgr.deleteActiveIfaces();
-
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth0"));
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth1"));
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth2"));
-}
-
// This test verifies that RFC6842 (echo client-id) compatibility may be
// configured.
TEST_F(CfgMgrTest, echoClientId) {
#include <dhcp/option.h>
#include <dhcp/option_custom.h>
#include <dhcp/option_int.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/dhcp_parsers.h>
class DhcpParserTest : public ::testing::Test {
public:
/// @brief Constructor
- ///
DhcpParserTest() {
- CfgMgr::instance().deleteActiveIfaces();
+ resetIfaceCfg();
+ }
+
+ /// @brief Destructor.
+ virtual ~DhcpParserTest() {
+ resetIfaceCfg();
+ }
+
+ /// @brief Resets selection of the interfaces from previous tests.
+ void resetIfaceCfg() {
+ CfgMgr::instance().getConfiguration()->iface_cfg_.closeSockets();
+ CfgMgr::instance().getConfiguration()->iface_cfg_.reset();
}
};
/// 4. Parses wildcard interface name and sets a CfgMgr flag which indicates
/// that server will listen on all interfaces.
TEST_F(DhcpParserTest, interfaceListParserTest) {
+ IfaceMgrTestConfig test_config(true);
const std::string name = "interfaces";
parser(new InterfaceListConfigParser(name));
ElementPtr list_element = Element::createList();
list_element->add(Element::create("eth0"));
- list_element->add(Element::create("eth1"));
-
- // Make sure there are no interfaces added yet.
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth0"));
- ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth1"));
// This should parse the configuration and add eth0 and eth1 to the list
// of interfaces that server should listen on.
parser->build(list_element);
- parser->commit();
// Use CfgMgr instance to check if eth0 and eth1 was added, and that
// eth2 was not added.
- CfgMgr& cfg_mgr = CfgMgr::instance();
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth0"));
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth1"));
- EXPECT_FALSE(cfg_mgr.isActiveIface("eth2"));
+ ConfigurationPtr cfg = CfgMgr::instance().getConfiguration();
+ ASSERT_TRUE(cfg);
+ ASSERT_NO_THROW(cfg->iface_cfg_.openSockets(10000));
+
+ EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
+ EXPECT_FALSE(test_config.socketOpen("eth1", AF_INET));
// Add keyword all to the configuration. This should activate all
// interfaces, including eth2, even though it has not been explicitly
// added.
list_element->add(Element::create("*"));
- // Reset parser's state.
+ // Reset parser and configuration.
parser.reset(new InterfaceListConfigParser(name));
+ cfg->iface_cfg_.closeSockets();
+ cfg->iface_cfg_.reset();
+
parser->build(list_element);
- parser->commit();
+ ASSERT_NO_THROW(cfg->iface_cfg_.openSockets(10000));
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth0"));
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth1"));
- EXPECT_TRUE(cfg_mgr.isActiveIface("eth2"));
+ EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
+ EXPECT_TRUE(test_config.socketOpen("eth1", AF_INET));
}
// Checks whether option space can be detected as vendor-id
bool
IfaceCfgTest::socketOpen(const std::string& iface_name,
const int family) const {
- Iface* iface = IfaceMgr::instance().getIface(iface_name);
- if (iface == NULL) {
- ADD_FAILURE() << "No such interface '" << iface_name << "'";
- return (false);
- }
-
- const Iface::SocketCollection& sockets = iface->getSockets();
- for (Iface::SocketCollection::const_iterator sock = sockets.begin();
- sock != sockets.end(); ++sock) {
- if (sock->family_ == family) {
- return (true);
- }
- }
- return (false);
+ return (iface_mgr_test_config_.socketOpen(iface_name, family));
}
-
bool
IfaceCfgTest::unicastOpen(const std::string& iface_name) const {
- Iface* iface = IfaceMgr::instance().getIface(iface_name);
- if (iface == NULL) {
- ADD_FAILURE() << "No such interface '" << iface_name << "'";
- return (false);
- }
-
- const Iface::SocketCollection& sockets = iface->getSockets();
- for (Iface::SocketCollection::const_iterator sock = sockets.begin();
- sock != sockets.end(); ++sock) {
- if ((!sock->addr_.isV6LinkLocal()) &&
- (!sock->addr_.isV6Multicast())) {
- return (true);
- }
- }
- return (false);
+ return (iface_mgr_test_config_.unicastOpen(iface_name));
}
// This test checks that the interface names can be explicitly selected