Browse Source

[3512] DHCP servers now use the IfaceCfg class for selecting interfaces.

Marcin Siodelski 10 years ago
parent
commit
c3b0803c9c

+ 2 - 1
src/bin/dhcp4/bundy_controller.cc

@@ -177,7 +177,8 @@ void ControlledDhcpv4Srv::init(const std::string& config_file) {
 
 
         // Configuration may disable or enable interfaces so we have to
         // Configuration may disable or enable interfaces so we have to
         // reopen sockets according to new configuration.
         // reopen sockets according to new configuration.
-        openActiveSockets(getPort(), useBroadcast());
+        CfgMgr::instance().getConfiguration()->iface_cfg_
+            .openSockets(getPort(), useBroadcast());
 
 
     } catch (const std::exception& ex) {
     } catch (const std::exception& ex) {
         LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(ex.what());
         LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(ex.what());

+ 5 - 2
src/bin/dhcp4/ctrl_dhcp4_srv.cc

@@ -18,6 +18,7 @@
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp4/dhcp4_log.h>
 #include <hooks/hooks_manager.h>
 #include <hooks/hooks_manager.h>
 #include <dhcp4/json_config_parser.h>
 #include <dhcp4/json_config_parser.h>
+#include <dhcpsrv/cfgmgr.h>
 
 
 using namespace isc::data;
 using namespace isc::data;
 using namespace isc::hooks;
 using namespace isc::hooks;
@@ -117,7 +118,7 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
         err << "Server object not initialized, can't process config.";
         err << "Server object not initialized, can't process config.";
         return (isc::config::createAnswer(1, err.str()));
         return (isc::config::createAnswer(1, err.str()));
     }
     }
-    
+
     ConstElementPtr answer = configureDhcp4Server(*srv, config);
     ConstElementPtr answer = configureDhcp4Server(*srv, config);
 
 
 
 
@@ -148,7 +149,9 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
     // safe and we really don't want to emit exceptions to whoever called this
     // safe and we really don't want to emit exceptions to whoever called this
     // method. Instead, catch an exception and create appropriate answer.
     // method. Instead, catch an exception and create appropriate answer.
     try {
     try {
-        srv->openActiveSockets(srv->getPort(), getInstance()->useBroadcast());
+        CfgMgr::instance().getConfiguration()->iface_cfg_
+            .openSockets(srv->getPort(), getInstance()->useBroadcast());
+
     } catch (std::exception& ex) {
     } catch (std::exception& ex) {
         err << "failed to open sockets after server reconfiguration: "
         err << "failed to open sockets after server reconfiguration: "
             << ex.what();
             << ex.what();

+ 0 - 49
src/bin/dhcp4/dhcp4_srv.cc

@@ -1795,55 +1795,6 @@ Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
     }
     }
 }
 }
 
 
-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
 size_t
 Dhcpv4Srv::unpackOptions(const OptionBuffer& buf,
 Dhcpv4Srv::unpackOptions(const OptionBuffer& buf,
                          const std::string& option_space,
                          const std::string& option_space,

+ 0 - 16
src/bin/dhcp4/dhcp4_srv.h

@@ -128,11 +128,6 @@ public:
     ///
     ///
     /// @name Public accessors returning values required to (re)open sockets.
     /// @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 Get UDP port on which server should listen.
@@ -154,17 +149,6 @@ public:
     }
     }
     //@}
     //@}
 
 
-    /// @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.
     /// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled.
     ///
     ///
     /// If updates are enabled, it Instructs the D2ClientMgr singleton to
     /// If updates are enabled, it Instructs the D2ClientMgr singleton to

+ 17 - 13
src/bin/dhcp4/tests/config_parser_unittest.cc

@@ -25,6 +25,7 @@
 #include <dhcp/option_int.h>
 #include <dhcp/option_int.h>
 #include <dhcp/docsis3_option_defs.h>
 #include <dhcp/docsis3_option_defs.h>
 #include <dhcp/classify.h>
 #include <dhcp/classify.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/testutils/config_result_check.h>
 #include <dhcpsrv/testutils/config_result_check.h>
@@ -77,7 +78,6 @@ public:
         // deal with sockets here, just check if configuration handling
         // deal with sockets here, just check if configuration handling
         // is sane.
         // is sane.
         srv_.reset(new Dhcpv4Srv(0));
         srv_.reset(new Dhcpv4Srv(0));
-        CfgMgr::instance().deleteActiveIfaces();
         // Create fresh context.
         // Create fresh context.
         globalContext()->copyContext(ParserContext(Option::V4));
         globalContext()->copyContext(ParserContext(Option::V4));
     }
     }
@@ -2895,6 +2895,8 @@ TEST_F(Dhcp4ParserTest, LibrariesSpecified) {
 // This test verifies that it is possible to select subset of interfaces
 // This test verifies that it is possible to select subset of interfaces
 // on which server should listen.
 // on which server should listen.
 TEST_F(Dhcp4ParserTest, selectedInterfaces) {
 TEST_F(Dhcp4ParserTest, selectedInterfaces) {
+    IfaceMgrTestConfig test_config(true);
+
     ConstElementPtr x;
     ConstElementPtr x;
     string config = "{ \"interfaces\": [ \"eth0\", \"eth1\" ],"
     string config = "{ \"interfaces\": [ \"eth0\", \"eth1\" ],"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
@@ -2907,24 +2909,26 @@ TEST_F(Dhcp4ParserTest, selectedInterfaces) {
 
 
     // Make sure the config manager is clean and there is no hanging
     // Make sure the config manager is clean and there is no hanging
     // interface configuration.
     // 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.
     // Apply configuration.
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     ASSERT_TRUE(status);
     ASSERT_TRUE(status);
     checkResult(status, 0);
     checkResult(status, 0);
 
 
+    CfgMgr::instance().getConfiguration()->iface_cfg_.openSockets(10000);
+
     // eth0 and eth1 were explicitly selected. eth2 was not.
     // 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
 // This test verifies that it is possible to configure the server in such a way
 // that it listens on all interfaces.
 // that it listens on all interfaces.
 TEST_F(Dhcp4ParserTest, allInterfaces) {
 TEST_F(Dhcp4ParserTest, allInterfaces) {
+    IfaceMgrTestConfig test_config(true);
+
     ConstElementPtr x;
     ConstElementPtr x;
     // This configuration specifies two interfaces on which server should listen
     // This configuration specifies two interfaces on which server should listen
     // but it also includes asterisk. The asterisk switches server into the
     // but it also includes asterisk. The asterisk switches server into the
@@ -2940,19 +2944,19 @@ TEST_F(Dhcp4ParserTest, allInterfaces) {
     ConstElementPtr status;
     ConstElementPtr status;
 
 
     // Make sure there is no old configuration.
     // 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.
     // Apply configuration.
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     ASSERT_TRUE(status);
     ASSERT_TRUE(status);
     checkResult(status, 0);
     checkResult(status, 0);
 
 
+    CfgMgr::instance().getConfiguration()->iface_cfg_.openSockets(10000);
+
     // All interfaces should be now active.
     // 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
 // This test checks the ability of the server to parse a configuration

+ 2 - 22
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc

@@ -420,26 +420,6 @@ TEST_F(Dhcpv4SrvTest, basic) {
     ASSERT_NO_THROW(naked_srv.reset(new NakedDhcpv4Srv(0)));
     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,
 // Verifies that DISCOVER message can be processed correctly,
 // that the OFFER message generated in response is valid and
 // that the OFFER message generated in response is valid and
 // contains necessary options.
 // contains necessary options.
@@ -2970,7 +2950,7 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsORO) {
     NakedDhcpv4Srv srv(0);
     NakedDhcpv4Srv srv(0);
 
 
     ConstElementPtr x;
     ConstElementPtr x;
-    string config = "{ \"interfaces\": [ \"all\" ],"
+    string config = "{ \"interfaces\": [ \"*\" ],"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
         "    \"option-data\": [ {"
         "    \"option-data\": [ {"
@@ -3055,7 +3035,7 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsORO) {
 // src/lib/dhcp/docsis3_option_defs.h.
 // src/lib/dhcp/docsis3_option_defs.h.
 TEST_F(Dhcpv4SrvTest, vendorOptionsDocsisDefinitions) {
 TEST_F(Dhcpv4SrvTest, vendorOptionsDocsisDefinitions) {
     ConstElementPtr x;
     ConstElementPtr x;
-    string config_prefix = "{ \"interfaces\": [ \"all\" ],"
+    string config_prefix = "{ \"interfaces\": [ \"*\" ],"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
         "    \"option-data\": [ {"
         "    \"option-data\": [ {"

+ 2 - 1
src/bin/dhcp4/tests/dhcp4_test_utils.cc

@@ -45,7 +45,7 @@ Dhcpv4SrvTest::Dhcpv4SrvTest()
     pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110")));
     pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110")));
     subnet_->addPool(pool_);
     subnet_->addPool(pool_);
 
 
-    CfgMgr::instance().deleteActiveIfaces();
+    CfgMgr::instance().getConfiguration()->iface_cfg_.reset();
     CfgMgr::instance().deleteSubnets4();
     CfgMgr::instance().deleteSubnets4();
     CfgMgr::instance().addSubnet4(subnet_);
     CfgMgr::instance().addSubnet4(subnet_);
 
 
@@ -58,6 +58,7 @@ Dhcpv4SrvTest::Dhcpv4SrvTest()
 Dhcpv4SrvTest::~Dhcpv4SrvTest() {
 Dhcpv4SrvTest::~Dhcpv4SrvTest() {
 
 
     // Make sure that we revert to default value
     // Make sure that we revert to default value
+    CfgMgr::instance().getConfiguration()->iface_cfg_.reset();
     CfgMgr::instance().echoClientId(true);
     CfgMgr::instance().echoClientId(true);
 }
 }
 
 

+ 2 - 2
src/bin/dhcp4/tests/dora_unittest.cc

@@ -49,7 +49,7 @@ namespace {
 ///   - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
 ///   - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
 const char* DORA_CONFIGS[] = {
 const char* DORA_CONFIGS[] = {
 // Configuration 0
 // Configuration 0
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"valid-lifetime\": 600,"
         "\"valid-lifetime\": 600,"
         "\"subnet4\": [ { "
         "\"subnet4\": [ { "
         "    \"subnet\": \"10.0.0.0/24\", "
         "    \"subnet\": \"10.0.0.0/24\", "
@@ -86,7 +86,7 @@ const char* DORA_CONFIGS[] = {
     "}",
     "}",
 
 
 // Configuration 1
 // Configuration 1
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"valid-lifetime\": 600,"
         "\"valid-lifetime\": 600,"
         "\"subnet4\": [ { "
         "\"subnet4\": [ { "
         "    \"subnet\": \"192.0.2.0/24\", "
         "    \"subnet\": \"192.0.2.0/24\", "

+ 2 - 2
src/bin/dhcp4/tests/inform_unittest.cc

@@ -48,7 +48,7 @@ namespace {
 ///   - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
 ///   - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
 const char* INFORM_CONFIGS[] = {
 const char* INFORM_CONFIGS[] = {
 // Configuration 0
 // Configuration 0
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"valid-lifetime\": 600,"
         "\"valid-lifetime\": 600,"
         "\"subnet4\": [ { "
         "\"subnet4\": [ { "
         "    \"subnet\": \"10.0.0.0/24\", "
         "    \"subnet\": \"10.0.0.0/24\", "
@@ -85,7 +85,7 @@ const char* INFORM_CONFIGS[] = {
     "}",
     "}",
 
 
 // Configuration 1
 // Configuration 1
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"valid-lifetime\": 600,"
         "\"valid-lifetime\": 600,"
         "\"subnet4\": [ { "
         "\"subnet4\": [ { "
         "    \"subnet\": \"192.0.2.0/24\", "
         "    \"subnet\": \"192.0.2.0/24\", "

+ 6 - 2
src/bin/dhcp6/ctrl_dhcp6_srv.cc

@@ -14,6 +14,7 @@
 
 
 #include <config.h>
 #include <config.h>
 #include <cc/data.h>
 #include <cc/data.h>
+#include <dhcpsrv/cfgmgr.h>
 #include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcp6/dhcp6_log.h>
 #include <dhcp6/dhcp6_log.h>
 #include <hooks/hooks_manager.h>
 #include <hooks/hooks_manager.h>
@@ -143,10 +144,13 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
     // safe and we really don't want to emit exceptions to the callback caller.
     // safe and we really don't want to emit exceptions to the callback caller.
     // Instead, catch an exception and create appropriate answer.
     // Instead, catch an exception and create appropriate answer.
     try {
     try {
-        srv->openActiveSockets(srv->getPort());
+        CfgMgr::instance().getConfiguration()->iface_cfg_
+            .openSockets(srv->getPort());
+
     } catch (const std::exception& ex) {
     } catch (const std::exception& ex) {
         std::ostringstream err;
         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());
         answer = isc::config::createAnswer(1, err.str());
     }
     }
 
 

+ 6 - 58
src/bin/dhcp6/dhcp6_srv.cc

@@ -150,6 +150,12 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
         // Instantiate allocation engine
         // Instantiate allocation engine
         alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
         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
         /// @todo call loadLibraries() when handling configuration changes
 
 
     } catch (const std::exception &e) {
     } catch (const std::exception &e) {
@@ -2429,64 +2435,6 @@ Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
     return reply;
     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
 size_t
 Dhcpv6Srv::unpackOptions(const OptionBuffer& buf,
 Dhcpv6Srv::unpackOptions(const OptionBuffer& buf,
                          const std::string& option_space,
                          const std::string& option_space,

+ 0 - 16
src/bin/dhcp6/dhcp6_srv.h

@@ -100,27 +100,11 @@ public:
     /// Typically, server listens on UDP port 547. Other ports are only
     /// Typically, server listens on UDP port 547. Other ports are only
     /// used for testing purposes.
     /// 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.
     /// @return UDP port on which server should listen.
     uint16_t getPort() const {
     uint16_t getPort() const {
         return (port_);
         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.
     /// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled.
     ///
     ///
     /// If updates are enabled, it Instructs the D2ClientMgr singleton to
     /// If updates are enabled, it Instructs the D2ClientMgr singleton to

+ 23 - 21
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -20,6 +20,7 @@
 #include <dhcp/iface_mgr.h>
 #include <dhcp/iface_mgr.h>
 #include <dhcp/option_custom.h>
 #include <dhcp/option_custom.h>
 #include <dhcp/option_int.h>
 #include <dhcp/option_int.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcp6/json_config_parser.h>
 #include <dhcp6/json_config_parser.h>
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcpsrv/addr_utilities.h>
 #include <dhcpsrv/addr_utilities.h>
@@ -74,7 +75,8 @@ public:
         // deal with sockets here, just check if configuration handling
         // deal with sockets here, just check if configuration handling
         // is sane.
         // is sane.
 
 
-        const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
+        const IfaceMgr::IfaceCollection& ifaces =
+            IfaceMgr::instance().getIfaces();
 
 
         // There must be some interface detected
         // There must be some interface detected
         if (ifaces.empty()) {
         if (ifaces.empty()) {
@@ -341,7 +343,7 @@ public:
     /// test to make sure that contents of the database do not affect the
     /// test to make sure that contents of the database do not affect the
     /// results of subsequent tests.
     /// results of subsequent tests.
     void resetConfiguration() {
     void resetConfiguration() {
-        string config = "{ \"interfaces\": [ \"all\" ],"
+        string config = "{ \"interfaces\": [ \"*\" ],"
             "\"hooks-libraries\": [ ],"
             "\"hooks-libraries\": [ ],"
             "\"preferred-lifetime\": 3000,"
             "\"preferred-lifetime\": 3000,"
             "\"rebind-timer\": 2000, "
             "\"rebind-timer\": 2000, "
@@ -357,7 +359,9 @@ public:
         // properly test interface configuration we disable listening on
         // properly test interface configuration we disable listening on
         // all interfaces before each test and later check that this setting
         // all interfaces before each test and later check that this setting
         // has been overriden by the configuration used in the test.
         // 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.
         // Create fresh context.
         globalContext()->copyContext(ParserContext(Option::V6));
         globalContext()->copyContext(ParserContext(Option::V6));
     }
     }
@@ -2892,7 +2896,7 @@ buildHooksLibrariesConfig(const std::vector<std::string>& libraries) {
 
 
     // Create the first part of the configuration string.
     // Create the first part of the configuration string.
     string config =
     string config =
-        "{ \"interfaces\": [ \"all\" ],"
+        "{ \"interfaces\": [ \"*\" ],"
             "\"hooks-libraries\": [";
             "\"hooks-libraries\": [";
 
 
     // Append the libraries (separated by commas if needed)
     // Append the libraries (separated by commas if needed)
@@ -3030,15 +3034,15 @@ TEST_F(Dhcp6ParserTest, LibrariesSpecified) {
 // This test verifies that it is possible to select subset of interfaces on
 // This test verifies that it is possible to select subset of interfaces on
 // which server should listen.
 // which server should listen.
 TEST_F(Dhcp6ParserTest, selectedInterfaces) {
 TEST_F(Dhcp6ParserTest, selectedInterfaces) {
+    IfaceMgrTestConfig test_config(true);
 
 
     // Make sure there is no garbage interface configuration in the CfgMgr.
     // 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;
     ConstElementPtr status;
 
 
-    string config = "{ \"interfaces\": [ \"eth0\", \"eth1\" ],"
+    string config = "{ \"interfaces\": [ \"eth0\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
@@ -3053,20 +3057,20 @@ TEST_F(Dhcp6ParserTest, selectedInterfaces) {
     // as the pool does not belong to that subnet
     // as the pool does not belong to that subnet
     checkResult(status, 0);
     checkResult(status, 0);
 
 
+    CfgMgr::instance().getConfiguration()->iface_cfg_.openSockets(10000);
+
     // eth0 and eth1 were explicitly selected. eth2 was not.
     // 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
 // This test verifies that it is possible to configure the server to listen on
 // all interfaces.
 // all interfaces.
 TEST_F(Dhcp6ParserTest, allInterfaces) {
 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;
     ConstElementPtr status;
 
 
@@ -3084,15 +3088,13 @@ TEST_F(Dhcp6ParserTest, allInterfaces) {
     ElementPtr json = Element::fromJSON(config);
     ElementPtr json = Element::fromJSON(config);
 
 
     EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
     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);
     checkResult(status, 0);
 
 
+    CfgMgr::instance().getConfiguration()->iface_cfg_.openSockets(10000);
+
     // All interfaces should be now active.
     // 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));
 }
 }
 
 
 
 

+ 2 - 2
src/bin/dhcp6/tests/confirm_unittest.cc

@@ -42,7 +42,7 @@ namespace {
 ///
 ///
 const char* CONFIRM_CONFIGS[] = {
 const char* CONFIRM_CONFIGS[] = {
 // Configuration 0
 // Configuration 0
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
@@ -61,7 +61,7 @@ const char* CONFIRM_CONFIGS[] = {
         "\"valid-lifetime\": 4000 }",
         "\"valid-lifetime\": 4000 }",
 
 
 // Configuration 1
 // Configuration 1
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "

+ 1 - 1
src/bin/dhcp6/tests/d2_unittest.cc

@@ -75,7 +75,7 @@ Dhcp6SrvD2Test::buildTestNcr(uint32_t dhcid_id_num) {
 
 
 void
 void
 Dhcp6SrvD2Test::reset() {
 Dhcp6SrvD2Test::reset() {
-    std::string config = "{ \"interfaces\": [ \"all\" ],"
+    std::string config = "{ \"interfaces\": [ \"*\" ],"
             "\"hooks-libraries\": [ ],"
             "\"hooks-libraries\": [ ],"
             "\"preferred-lifetime\": 3000,"
             "\"preferred-lifetime\": 3000,"
             "\"rebind-timer\": 2000, "
             "\"rebind-timer\": 2000, "

+ 3 - 3
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -289,7 +289,7 @@ TEST_F(Dhcpv6SrvTest, advertiseOptions) {
     IfaceMgrTestConfig test_config(true);
     IfaceMgrTestConfig test_config(true);
 
 
     ConstElementPtr x;
     ConstElementPtr x;
-    string config = "{ \"interfaces\": [ \"all\" ],"
+    string config = "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
@@ -1557,7 +1557,7 @@ TEST_F(Dhcpv6SrvTest, vendorOptionsORO) {
 
 
     IfaceMgrTestConfig test_config(true);
     IfaceMgrTestConfig test_config(true);
 
 
-    string config = "{ \"interfaces\": [ \"all\" ],"
+    string config = "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
@@ -1642,7 +1642,7 @@ TEST_F(Dhcpv6SrvTest, vendorOptionsORO) {
 // src/lib/dhcp/docsis3_option_defs.h.
 // src/lib/dhcp/docsis3_option_defs.h.
 TEST_F(Dhcpv6SrvTest, vendorOptionsDocsisDefinitions) {
 TEST_F(Dhcpv6SrvTest, vendorOptionsDocsisDefinitions) {
     ConstElementPtr x;
     ConstElementPtr x;
-    string config_prefix = "{ \"interfaces\": [ \"all\" ],"
+    string config_prefix = "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "

+ 6 - 6
src/bin/dhcp6/tests/rebind_unittest.cc

@@ -64,7 +64,7 @@ namespace {
 ///   - this specific configuration is used by tests which don't use relays
 ///   - this specific configuration is used by tests which don't use relays
 const char* REBIND_CONFIGS[] = {
 const char* REBIND_CONFIGS[] = {
 // Configuration 0
 // Configuration 0
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
@@ -83,7 +83,7 @@ const char* REBIND_CONFIGS[] = {
         "\"valid-lifetime\": 4000 }",
         "\"valid-lifetime\": 4000 }",
 
 
 // Configuration 1
 // Configuration 1
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
@@ -102,7 +102,7 @@ const char* REBIND_CONFIGS[] = {
         "\"valid-lifetime\": 4000 }",
         "\"valid-lifetime\": 4000 }",
 
 
 // Configuration 2
 // Configuration 2
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
@@ -121,7 +121,7 @@ const char* REBIND_CONFIGS[] = {
         "\"valid-lifetime\": 4000 }",
         "\"valid-lifetime\": 4000 }",
 
 
 // Configuration 3
 // Configuration 3
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
@@ -140,7 +140,7 @@ const char* REBIND_CONFIGS[] = {
         "\"valid-lifetime\": 4000 }",
         "\"valid-lifetime\": 4000 }",
 
 
 // Configuration 4
 // Configuration 4
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "
@@ -167,7 +167,7 @@ const char* REBIND_CONFIGS[] = {
         "\"valid-lifetime\": 4000 }",
         "\"valid-lifetime\": 4000 }",
 
 
 // Configuration 5
 // Configuration 5
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "

+ 1 - 1
src/bin/dhcp6/tests/sarr_unittest.cc

@@ -31,7 +31,7 @@ namespace {
 ///   - prefixes of length 64, delegated from the pool: 2001:db8:3::/48
 ///   - prefixes of length 64, delegated from the pool: 2001:db8:3::/48
 const char* CONFIGS[] = {
 const char* CONFIGS[] = {
     // Configuration 0
     // Configuration 0
-    "{ \"interfaces\": [ \"all\" ],"
+    "{ \"interfaces\": [ \"*\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"renew-timer\": 1000, "

+ 36 - 0
src/lib/dhcp/tests/iface_mgr_test_config.cc

@@ -141,6 +141,42 @@ IfaceMgrTestConfig::setIfaceFlags(const std::string& name,
     iface->inactive6_ = inactive6.flag_;
     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);
+}
+
 }
 }
 }
 }
 }
 }

+ 12 - 0
src/lib/dhcp/tests/iface_mgr_test_config.h

@@ -229,6 +229,18 @@ public:
                        const FlagInactive4& inactive4,
                        const FlagInactive4& inactive4,
                        const FlagInactive6& inactive6);
                        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:
 private:
     /// @brief Currently used packet filter for DHCPv4.
     /// @brief Currently used packet filter for DHCPv4.
     PktFilterPtr packet_filter4_;
     PktFilterPtr packet_filter4_;

+ 1 - 82
src/lib/dhcpsrv/cfgmgr.cc

@@ -314,77 +314,6 @@ std::string CfgMgr::getDataDir() {
     return (datadir_);
     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
 bool
 CfgMgr::isDuplicate(const Subnet4& subnet) const {
 CfgMgr::isDuplicate(const Subnet4& subnet) const {
     for (Subnet4Collection::const_iterator subnet_it = subnets4_.begin();
     for (Subnet4Collection::const_iterator subnet_it = subnets4_.begin();
@@ -408,15 +337,6 @@ CfgMgr::isDuplicate(const Subnet6& subnet) const {
 }
 }
 
 
 
 
-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
 void
 CfgMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
 CfgMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
     d2_client_mgr_.setD2ClientConfig(new_config);
     d2_client_mgr_.setD2ClientConfig(new_config);
@@ -443,8 +363,7 @@ CfgMgr::getConfiguration() {
 }
 }
 
 
 CfgMgr::CfgMgr()
 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()) {
       d2_client_mgr_(), configuration_(new Configuration()) {
     // DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
     // 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
     // Note: the definition of DHCP_DATA_DIR needs to include quotation marks

+ 0 - 78
src/lib/dhcpsrv/cfgmgr.h

@@ -334,54 +334,6 @@ public:
     /// @return data directory
     /// @return data directory
     std::string getDataDir();
     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
     /// @brief Sets whether server should send back client-id in DHCPv4
     ///
     ///
     /// This is a compatibility flag. The default (true) is compliant with
     /// This is a compatibility flag. The default (true) is compliant with
@@ -458,20 +410,6 @@ protected:
 
 
 private:
 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.
     /// @brief Checks that the IPv4 subnet with the given id already exists.
     ///
     ///
     /// @param subnet Subnet for which this function will check if the other
     /// @param subnet Subnet for which this function will check if the other
@@ -502,22 +440,6 @@ private:
     /// @brief directory where data files (e.g. server-id) are stored
     /// @brief directory where data files (e.g. server-id) are stored
     std::string datadir_;
     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
     /// Indicates whether v4 server should send back client-id
     bool echo_v4_client_id_;
     bool echo_v4_client_id_;
 
 

+ 8 - 0
src/lib/dhcpsrv/configuration.h

@@ -15,6 +15,7 @@
 #ifndef DHCPSRV_CONFIGURATION_H
 #ifndef DHCPSRV_CONFIGURATION_H
 #define DHCPSRV_CONFIGURATION_H
 #define DHCPSRV_CONFIGURATION_H
 
 
+#include <dhcpsrv/iface_cfg.h>
 #include <log/logger_level.h>
 #include <log/logger_level.h>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
 #include <vector>
 #include <vector>
@@ -84,6 +85,13 @@ struct Configuration {
 
 
     /// @brief logging specific information
     /// @brief logging specific information
     LoggingInfoStorage logging_info_;
     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
 /// @brief pointer to the configuration

+ 8 - 42
src/lib/dhcpsrv/dhcp_parsers.cc

@@ -36,10 +36,6 @@ using namespace isc::hooks;
 namespace isc {
 namespace isc {
 namespace dhcp {
 namespace dhcp {
 
 
-namespace {
-const char* ALL_IFACES_KEYWORD = "*";
-}
-
 // *********************** ParserContext  *************************
 // *********************** ParserContext  *************************
 
 
 ParserContext::ParserContext(Option::Universe universe):
 ParserContext::ParserContext(Option::Universe universe):
@@ -194,53 +190,23 @@ InterfaceListConfigParser(const std::string& param_name)
 
 
 void
 void
 InterfaceListConfigParser::build(ConstElementPtr value) {
 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()) {
     BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
         std::string iface_name = iface->stringValue();
         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
 void
 InterfaceListConfigParser::commit() {
 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
 bool

+ 1 - 1
src/lib/dhcpsrv/dhcp_parsers.h

@@ -406,7 +406,7 @@ public:
     /// @param value pointer to the content of parsed values
     /// @param value pointer to the content of parsed values
     virtual void build(isc::data::ConstElementPtr value);
     virtual void build(isc::data::ConstElementPtr value);
 
 
-    /// @brief commits interfaces list configuration
+    /// @brief Does nothing.
     virtual void commit();
     virtual void commit();
 
 
 private:
 private:

+ 5 - 1
src/lib/dhcpsrv/dhcpsrv_messages.mes

@@ -54,10 +54,14 @@ consider reducing the lease lifetime.  In this way, addresses allocated
 to clients that are no longer active on the network will become available
 to clients that are no longer active on the network will become available
 available sooner.
 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
 A debug message issued when new interface is being added to the collection of
 interfaces on which server listens to DHCP messages.
 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
 % DHCPSRV_CFGMGR_ADD_SUBNET4 adding subnet %1
 A debug message reported when the DHCP configuration manager is adding the
 A debug message reported when the DHCP configuration manager is adding the
 specified IPv4 subnet to its database.
 specified IPv4 subnet to its database.

+ 18 - 9
src/lib/dhcpsrv/iface_cfg.cc

@@ -84,6 +84,9 @@ IfaceCfg::openSockets(const uint16_t port, const bool use_bcast) {
         }
         }
     }
     }
 
 
+    // Before opening any sockets, close existing ones.
+    closeSockets();
+
     // Set the callback which is called when the socket fails to open
     // Set the callback which is called when the socket fails to open
     // for some specific interface. This callback will simply log a
     // for some specific interface. This callback will simply log a
     // warning message.
     // warning message.
@@ -154,17 +157,26 @@ IfaceCfg::use(const std::string& iface_name) {
                           << "' doesn't exist in the system");
                           << "' 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
                 isc_throw(DuplicateIfaceName, "interface '" << name
                           << "' has already been specified");
                           << "' 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_) {
         } else if (wildcard_used_) {
             isc_throw(DuplicateIfaceName, "the wildcard interface '"
             isc_throw(DuplicateIfaceName, "the wildcard interface '"
                       << ALL_IFACES_KEYWORD << "' can only be specified once");
                       << ALL_IFACES_KEYWORD << "' can only be specified once");
 
 
         } else {
         } else {
+            LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
+                      DHCPSRV_CFGMGR_ALL_IFACES_ACTIVE);
             wildcard_used_ = true;
             wildcard_used_ = true;
 
 
         }
         }
@@ -231,18 +243,15 @@ IfaceCfg::use(const std::string& iface_name) {
 
 
         // Insert address and the interface to the collection of unicast
         // Insert address and the interface to the collection of unicast
         // addresses.
         // 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 '"
             isc_throw(DuplicateIfaceName, "must not specify unicast address '"
                       << addr << "' for interface '" << name << "' "
                       << addr << "' for interface '" << name << "' "
                       "because other unicast address has already been"
                       "because other unicast address has already been"
                       " specified for this interface");
                       " 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));
     }
     }
 
 
 }
 }

+ 0 - 80
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc

@@ -265,7 +265,6 @@ public:
         CfgMgr::instance().deleteSubnets4();
         CfgMgr::instance().deleteSubnets4();
         CfgMgr::instance().deleteSubnets6();
         CfgMgr::instance().deleteSubnets6();
         CfgMgr::instance().deleteOptionDefs();
         CfgMgr::instance().deleteOptionDefs();
-        CfgMgr::instance().deleteActiveIfaces();
     }
     }
 
 
     /// @brief generates interface-id option based on provided text
     /// @brief generates interface-id option based on provided text
@@ -983,85 +982,6 @@ TEST_F(CfgMgrTest, optionSpace6) {
     /// @todo decide if a duplicate vendor space is allowed.
     /// @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
 // This test verifies that RFC6842 (echo client-id) compatibility may be
 // configured.
 // configured.
 TEST_F(CfgMgrTest, echoClientId) {
 TEST_F(CfgMgrTest, echoClientId) {

+ 27 - 17
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc

@@ -18,6 +18,7 @@
 #include <dhcp/option.h>
 #include <dhcp/option.h>
 #include <dhcp/option_custom.h>
 #include <dhcp/option_custom.h>
 #include <dhcp/option_int.h>
 #include <dhcp/option_int.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/dhcp_parsers.h>
 #include <dhcpsrv/dhcp_parsers.h>
@@ -47,9 +48,19 @@ namespace {
 class DhcpParserTest : public ::testing::Test {
 class DhcpParserTest : public ::testing::Test {
 public:
 public:
     /// @brief Constructor
     /// @brief Constructor
-    ///
     DhcpParserTest() {
     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();
     }
     }
 };
 };
 
 
@@ -210,6 +221,7 @@ TEST_F(DhcpParserTest, uint32ParserTest) {
 /// 4. Parses wildcard interface name and sets a CfgMgr flag which indicates
 /// 4. Parses wildcard interface name and sets a CfgMgr flag which indicates
 /// that server will listen on all interfaces.
 /// that server will listen on all interfaces.
 TEST_F(DhcpParserTest, interfaceListParserTest) {
 TEST_F(DhcpParserTest, interfaceListParserTest) {
+    IfaceMgrTestConfig test_config(true);
 
 
     const std::string name = "interfaces";
     const std::string name = "interfaces";
 
 
@@ -220,37 +232,35 @@ TEST_F(DhcpParserTest, interfaceListParserTest) {
         parser(new InterfaceListConfigParser(name));
         parser(new InterfaceListConfigParser(name));
     ElementPtr list_element = Element::createList();
     ElementPtr list_element = Element::createList();
     list_element->add(Element::create("eth0"));
     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
     // This should parse the configuration and add eth0 and eth1 to the list
     // of interfaces that server should listen on.
     // of interfaces that server should listen on.
     parser->build(list_element);
     parser->build(list_element);
-    parser->commit();
 
 
     // Use CfgMgr instance to check if eth0 and eth1 was added, and that
     // Use CfgMgr instance to check if eth0 and eth1 was added, and that
     // eth2 was not added.
     // 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
     // Add keyword all to the configuration. This should activate all
     // interfaces, including eth2, even though it has not been explicitly
     // interfaces, including eth2, even though it has not been explicitly
     // added.
     // added.
     list_element->add(Element::create("*"));
     list_element->add(Element::create("*"));
 
 
-    // Reset parser's state.
+    // Reset parser and configuration.
     parser.reset(new InterfaceListConfigParser(name));
     parser.reset(new InterfaceListConfigParser(name));
+    cfg->iface_cfg_.closeSockets();
+    cfg->iface_cfg_.reset();
+
     parser->build(list_element);
     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
 // Checks whether option space can be detected as vendor-id

+ 2 - 30
src/lib/dhcpsrv/tests/iface_cfg_unittest.cc

@@ -55,39 +55,11 @@ public:
 bool
 bool
 IfaceCfgTest::socketOpen(const std::string& iface_name,
 IfaceCfgTest::socketOpen(const std::string& iface_name,
                          const int family) const {
                          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
 bool
 IfaceCfgTest::unicastOpen(const std::string& iface_name) const {
 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
 // This test checks that the interface names can be explicitly selected