Parcourir la source

[3587] Use CfgSubnets4 object to obtain information about subnets.

Marcin Siodelski il y a 10 ans
Parent
commit
feb21c04b9

+ 13 - 41
src/bin/dhcp4/dhcp4_srv.cc

@@ -29,6 +29,7 @@
 #include <dhcpsrv/addr_utilities.h>
 #include <dhcpsrv/callout_handle_store.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/cfg_subnets4.h>
 #include <dhcpsrv/lease_mgr.h>
 #include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/subnet.h>
@@ -1539,47 +1540,17 @@ Subnet4Ptr
 Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) const {
 
     Subnet4Ptr subnet;
-    static const IOAddress notset("0.0.0.0");
-    static const IOAddress bcast("255.255.255.255");
 
-    // If a message is relayed, use the relay (giaddr) address to select subnet
-    // for the client. Note that this may result in exception if the value
-    // of hops does not correspond with the Giaddr. Such message is considered
-    // to be malformed anyway and the message will be dropped by the higher
-    // level functions.
-    if (question->isRelayed()) {
-        subnet = CfgMgr::instance().getSubnet4(question->getGiaddr(),
-                                               question->classes_,
-                                               true);
-
-    // The message is not relayed so it is sent directly by a client. But
-    // the client may be renewing its lease and in such case it unicasts
-    // its message to the server. Note that the unicast Request bypasses
-    // relays and the client may be in a different network, so we can't
-    // use IP address on the local interface to get the subnet. Instead,
-    // we rely on the client's address to get the subnet.
-    } else if ((question->getLocalAddr() != bcast) &&
-               (question->getCiaddr() != notset)) {
-        subnet = CfgMgr::instance().getSubnet4(question->getCiaddr(),
-                                               question->classes_);
-
-    // Either renewing client or the client that sends DHCPINFORM
-    // must set the ciaddr. But apparently some clients don't do it,
-    // so if the client didn't include ciaddr we will use the source
-    // address.
-    } else if ((question->getLocalAddr() != bcast) &&
-               (question->getRemoteAddr() != notset)) {
-        subnet = CfgMgr::instance().getSubnet4(question->getRemoteAddr(),
-                                               question->classes_);
-
-    // The message has been received from a directly connected client
-    // and this client appears to have no address. The IPv4 address
-    // assigned to the interface on which this message has been received,
-    // will be used to determine the subnet suitable for the client.
-    } else {
-        subnet = CfgMgr::instance().getSubnet4(question->getIface(),
-                                               question->classes_);
-    }
+    CfgSubnets4::Selector selector;
+    selector.ciaddr_ = question->getCiaddr();
+    selector.giaddr_ = question->getGiaddr();
+    selector.local_address_ = question->getLocalAddr();
+    selector.remote_address_ = question->getRemoteAddr();
+    selector.client_classes_ = question->classes_;
+    selector.iface_name_ = question->getIface();
+
+    CfgMgr& cfgmgr = CfgMgr::instance();
+    subnet = cfgmgr.getCurrentCfg()->getCfgSubnets4()->get(selector);
 
     // Let's execute all callouts registered for subnet4_select
     if (HooksManager::calloutsPresent(hook_index_subnet4_select_)) {
@@ -1592,7 +1563,8 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) const {
         callout_handle->setArgument("query4", question);
         callout_handle->setArgument("subnet4", subnet);
         callout_handle->setArgument("subnet4collection",
-                                    CfgMgr::instance().getSubnets4());
+                                    cfgmgr.getCurrentCfg()->
+                                    getCfgSubnets4()->getAll());
 
         // Call user (and server-side) callouts
         HooksManager::callCallouts(hook_index_subnet4_select_,

+ 3 - 23
src/bin/dhcp4/json_config_parser.cc

@@ -138,7 +138,7 @@ public:
             // subnet id is invalid (duplicate). Thus, we catch exceptions
             // here to append a position in the configuration string.
             try {
-                isc::dhcp::CfgMgr::instance().addSubnet4(sub4ptr);
+                CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(sub4ptr);
             } catch (const std::exception& ex) {
                 isc_throw(DhcpConfigError, ex.what() << " ("
                           << subnet->getPosition() << ")");
@@ -317,28 +317,16 @@ public:
     ///
     /// @param subnets_list pointer to a list of IPv4 subnets
     void build(ConstElementPtr subnets_list) {
-        // @todo: Implement more subtle reconfiguration than toss
-        // the old one and replace with the new one.
-
-        // remove old subnets
-        CfgMgr::instance().deleteSubnets4();
-
         BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
             ParserPtr parser(new Subnet4ConfigParser("subnet"));
             parser->build(subnet);
-            subnets_.push_back(parser);
         }
     }
 
     /// @brief commits subnets definitions.
     ///
-    /// Iterates over all Subnet4 parsers. Each parser contains definitions of
-    /// a single subnet and its parameters and commits each subnet separately.
+    /// Does nothing.
     void commit() {
-        BOOST_FOREACH(ParserPtr subnet, subnets_) {
-            subnet->commit();
-        }
-
     }
 
     /// @brief Returns Subnet4ListConfigParser object
@@ -347,10 +335,6 @@ public:
     static DhcpConfigParser* factory(const std::string& param_name) {
         return (new Subnets4ListConfigParser(param_name));
     }
-
-    /// @brief collection of subnet parsers.
-    ParserCollection subnets_;
-
 };
 
 } // anonymous namespace
@@ -545,10 +529,6 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
     // This operation should be exception safe but let's make sure.
     if (!rollback) {
         try {
-            if (subnet_parser) {
-                subnet_parser->commit();
-            }
-
             // No need to commit interface names as this is handled by the
             // CfgMgr::commit() function.
 
@@ -582,7 +562,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
     }
 
     LOG_INFO(dhcp4_logger, DHCP4_CONFIG_COMPLETE)
-        .arg(CfgMgr::instance().getCurrentCfg()->
+        .arg(CfgMgr::instance().getStagingCfg()->
              getConfigSummary(SrvConfig::CFGSEL_ALL4));
 
     // Everything was fine. Configuration is successful.

+ 68 - 49
src/bin/dhcp4/tests/config_parser_unittest.cc

@@ -28,6 +28,7 @@
 #include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/cfg_subnets4.h>
 #include <dhcpsrv/testutils/config_result_check.h>
 #include <hooks/hooks_manager.h>
 
@@ -235,8 +236,8 @@ public:
     getOptionFromSubnet(const IOAddress& subnet_address,
                         const uint16_t option_code,
                         const uint16_t expected_options_count = 1) {
-        Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(subnet_address,
-                                                          classify_);
+        Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+            getCfgSubnets4()->get(subnet_address);
         if (!subnet) {
             /// @todo replace toText() with the use of operator <<.
             ADD_FAILURE() << "A subnet for the specified address "
@@ -397,6 +398,7 @@ public:
     ///         latter case, a failure will have been added to the current test.
     bool
     executeConfiguration(const std::string& config, const char* operation) {
+        CfgMgr::instance().clear();
         ConstElementPtr status;
         try {
             ElementPtr json = Element::fromJSON(config);
@@ -532,8 +534,8 @@ TEST_F(Dhcp4ParserTest, unspecifiedRenewTimer) {
     checkGlobalUint32("rebind-timer", 2000);
     checkGlobalUint32("valid-lifetime", 4000);
 
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     EXPECT_TRUE(subnet->getT1().unspecified());
     EXPECT_FALSE(subnet->getT2().unspecified());
@@ -566,8 +568,8 @@ TEST_F(Dhcp4ParserTest, unspecifiedRebindTimer) {
     checkGlobalUint32("renew-timer", 1000);
     checkGlobalUint32("valid-lifetime", 4000);
 
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     EXPECT_FALSE(subnet->getT1().unspecified());
     EXPECT_EQ(1000, subnet->getT1());
@@ -601,8 +603,8 @@ TEST_F(Dhcp4ParserTest, subnetGlobalDefaults) {
 
     // Now check if the configuration was indeed handled and we have
     // expected pool configured.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     EXPECT_EQ(1000, subnet->getT1());
     EXPECT_EQ(2000, subnet->getT2());
@@ -649,7 +651,10 @@ TEST_F(Dhcp4ParserTest, multipleSubnets) {
         EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
         checkResult(x, 0);
 
-        const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
+        CfgMgr::instance().commit();
+
+        const Subnet4Collection* subnets =
+            CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
         ASSERT_TRUE(subnets);
         ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
 
@@ -702,7 +707,10 @@ TEST_F(Dhcp4ParserTest, multipleSubnetsExplicitIDs) {
         EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
         checkResult(x, 0);
 
-        const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
+        CfgMgr::instance().commit();
+
+        const Subnet4Collection* subnets =
+            CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
         ASSERT_TRUE(subnets);
         ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
 
@@ -833,16 +841,19 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) {
     EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
     checkResult(x, 0);
 
-    const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
+    const Subnet4Collection* subnets =
+        CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
 
+    CfgMgr::instance().clear();
+
     // Do the reconfiguration (the last subnet is removed)
     json = Element::fromJSON(config_first3);
     EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
     checkResult(x, 0);
 
-    subnets = CfgMgr::instance().getSubnets4();
+    subnets = CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(3, subnets->size()); // We expect 3 subnets now (4th is removed)
 
@@ -851,6 +862,8 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) {
     EXPECT_EQ(2, subnets->at(1)->getID());
     EXPECT_EQ(3, subnets->at(2)->getID());
 
+    CfgMgr::instance().clear();
+
     /// CASE 2: Configure 4 subnets, then reconfigure and remove one
     /// from in between (not first, not last)
 
@@ -859,12 +872,14 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) {
     EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
     checkResult(x, 0);
 
+    CfgMgr::instance().clear();
+
     // Do reconfiguration
     json = Element::fromJSON(config_second_removed);
     EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
     checkResult(x, 0);
 
-    subnets = CfgMgr::instance().getSubnets4();
+    subnets = CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(3, subnets->size()); // We expect 4 subnets
 
@@ -901,8 +916,8 @@ TEST_F(Dhcp4ParserTest, nextServerGlobal) {
 
     // Now check if the configuration was indeed handled and we have
     // expected pool configured.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText());
 }
@@ -931,8 +946,8 @@ TEST_F(Dhcp4ParserTest, nextServerSubnet) {
 
     // Now check if the configuration was indeed handled and we have
     // expected pool configured.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText());
 }
@@ -1022,8 +1037,8 @@ TEST_F(Dhcp4ParserTest, nextServerOverride) {
 
     // Now check if the configuration was indeed handled and we have
     // expected pool configured.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText());
 }
@@ -1061,6 +1076,8 @@ TEST_F(Dhcp4ParserTest, echoClientId) {
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json_false));
     ASSERT_FALSE(CfgMgr::instance().echoClientId());
 
+    CfgMgr::instance().clear();
+
     // Now check that "true" configuration is really applied.
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json_true));
     ASSERT_TRUE(CfgMgr::instance().echoClientId());
@@ -1093,8 +1110,8 @@ TEST_F(Dhcp4ParserTest, subnetLocal) {
     // returned value should be 0 (configuration success)
     checkResult(status, 0);
 
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     EXPECT_EQ(1, subnet->getT1());
     EXPECT_EQ(2, subnet->getT2());
@@ -1131,7 +1148,8 @@ TEST_F(Dhcp4ParserTest, multiplePools) {
     ASSERT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     checkResult(status, 0);
 
-    const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
+    const Subnet4Collection* subnets =
+        CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(2, subnets->size()); // We expect 2 subnets
 
@@ -1204,8 +1222,8 @@ TEST_F(Dhcp4ParserTest, poolPrefixLen) {
     // returned value must be 0 (configuration accepted)
     checkResult(status, 0);
 
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     EXPECT_EQ(1000, subnet->getT1());
     EXPECT_EQ(2000, subnet->getT2());
@@ -1794,8 +1812,8 @@ TEST_F(Dhcp4ParserTest, optionDataDefaults) {
     EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
     checkResult(x, 0);
 
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp4");
     ASSERT_EQ(2, options->size());
@@ -1880,8 +1898,8 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) {
     checkResult(status, 0);
 
     // Options should be now available for the subnet.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     // Try to get the option from the space dhcp4.
     OptionDescriptor desc1 = subnet->getCfgOption()->get("dhcp4", 56);
@@ -2034,8 +2052,8 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
     checkResult(status, 0);
 
     // Get the subnet.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.5"));
     ASSERT_TRUE(subnet);
 
     // We should have one option available.
@@ -2101,8 +2119,8 @@ TEST_F(Dhcp4ParserTest, optionDataInSingleSubnet) {
     EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
     checkResult(x, 0);
 
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.24"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.24"));
     ASSERT_TRUE(subnet);
     OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp4");
     ASSERT_EQ(2, options->size());
@@ -2252,8 +2270,8 @@ TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) {
     EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
     checkResult(x, 0);
 
-    Subnet4Ptr subnet1 = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.100"),
-                                                       classify_);
+    Subnet4Ptr subnet1 = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.100"));
     ASSERT_TRUE(subnet1);
     OptionContainerPtr options1 = subnet1->getCfgOption()->getAll("dhcp4");
     ASSERT_EQ(1, options1->size());
@@ -2277,8 +2295,8 @@ TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) {
     testOption(*range1.first, 56, foo_expected, sizeof(foo_expected));
 
     // Test another subnet in the same way.
-    Subnet4Ptr subnet2 = CfgMgr::instance().getSubnet4(IOAddress("192.0.3.102"),
-                                                       classify_);
+    Subnet4Ptr subnet2 = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.3.102"));
     ASSERT_TRUE(subnet2);
     OptionContainerPtr options2 = subnet2->getCfgOption()->getAll("dhcp4");
     ASSERT_EQ(1, options2->size());
@@ -2355,8 +2373,8 @@ TEST_F(Dhcp4ParserTest, optionDataLowerCase) {
     EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
     checkResult(x, 0);
 
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.5"));
     ASSERT_TRUE(subnet);
     OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp4");
     ASSERT_EQ(1, options->size());
@@ -2398,8 +2416,8 @@ TEST_F(Dhcp4ParserTest, stdOptionData) {
     EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
     checkResult(x, 0);
 
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.5"));
     ASSERT_TRUE(subnet);
     OptionContainerPtr options =
         subnet->getCfgOption()->getAll("dhcp4");
@@ -2606,8 +2624,8 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
     checkResult(status, 0);
 
     // Get the subnet.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.5"));
     ASSERT_TRUE(subnet);
 
     // We should have one option available.
@@ -2690,8 +2708,8 @@ TEST_F(Dhcp4ParserTest, vendorOptionsHex) {
     checkResult(status, 0);
 
     // Options should be now available for the subnet.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.5"));
     ASSERT_TRUE(subnet);
 
     // Try to get the option from the vendor space 4491
@@ -2751,8 +2769,8 @@ TEST_F(Dhcp4ParserTest, vendorOptionsCsv) {
     checkResult(status, 0);
 
     // Options should be now available for the subnet.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.5"));
     ASSERT_TRUE(subnet);
 
     // Try to get the option from the vendor space 4491
@@ -3127,8 +3145,8 @@ TEST_F(Dhcp4ParserTest, subnetRelayInfo) {
     // returned value should be 0 (configuration success)
     checkResult(status, 0);
 
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
+        getCfgSubnets4()->get(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     EXPECT_EQ("192.0.2.123", subnet->getRelayInfo().addr_.toText());
 }
@@ -3166,7 +3184,8 @@ TEST_F(Dhcp4ParserTest, classifySubnets) {
     EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
     checkResult(x, 0);
 
-    const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
+    const Subnet4Collection* subnets =
+        CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
 

+ 2 - 0
src/bin/dhcp4/tests/d2_unittest.cc

@@ -127,6 +127,8 @@ Dhcp4SrvD2Test::configure(const std::string& config, bool exp_result) {
     ElementPtr json = Element::fromJSON(config);
     ConstElementPtr status;
 
+    CfgMgr::instance().clear();
+
     // Configure the server and make sure the config is accepted
     EXPECT_NO_THROW(status = configureDhcp4Server(srv_, json));
     ASSERT_TRUE(status);

+ 24 - 8
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc

@@ -553,8 +553,9 @@ TEST_F(Dhcpv4SrvTest, DiscoverNoTimers) {
     pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"),
                                IOAddress("192.0.2.110")));
     subnet_->addPool(pool_);
-    CfgMgr::instance().deleteSubnets4();
-    CfgMgr::instance().addSubnet4(subnet_);
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(subnet_);
+    CfgMgr::instance().commit();
 
     // Pass it to the server and get an offer
     Pkt4Ptr offer = srv->processDiscover(dis);
@@ -741,8 +742,9 @@ TEST_F(Dhcpv4SrvTest, RequestNoTimers) {
     pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"),
                                IOAddress("192.0.2.110")));
     subnet_->addPool(pool_);
-    CfgMgr::instance().deleteSubnets4();
-    CfgMgr::instance().addSubnet4(subnet_);
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(subnet_);
+    CfgMgr::instance().commit();
 
     // Pass it to the server and get an ACK.
     Pkt4Ptr ack = srv->processRequest(req);
@@ -1207,6 +1209,8 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsDocsis) {
     comment_ = config::parseAnswer(rcode_, status);
     ASSERT_EQ(0, rcode_);
 
+    CfgMgr::instance().commit();
+
     // Let's create a relayed DISCOVER. This particular relayed DISCOVER has
     // added option 82 (relay agent info) with 3 suboptions. The server
     // is supposed to echo it back in its response.
@@ -1448,6 +1452,8 @@ TEST_F(Dhcpv4SrvTest, nextServerOverride) {
 
     EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
 
+    CfgMgr::instance().commit();
+
     // check if returned status is OK
     ASSERT_TRUE(status);
     comment_ = config::parseAnswer(rcode_, status);
@@ -1492,6 +1498,8 @@ TEST_F(Dhcpv4SrvTest, nextServerGlobal) {
 
     EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
 
+    CfgMgr::instance().commit();
+
     // check if returned status is OK
     ASSERT_TRUE(status);
     comment_ = config::parseAnswer(rcode_, status);
@@ -2513,7 +2521,8 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
     // Check that pkt4 argument passing was successful and returned proper value
     EXPECT_TRUE(callback_pkt4_.get() == sol.get());
 
-    const Subnet4Collection* exp_subnets = CfgMgr::instance().getSubnets4();
+    const Subnet4Collection* exp_subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
 
     // The server is supposed to pick the first subnet, because of matching
     // interface. Check that the value is reported properly.
@@ -2562,6 +2571,8 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectChange) {
     comment_ = config::parseAnswer(rcode_, status);
     ASSERT_EQ(0, rcode_);
 
+    CfgMgr::instance().commit();
+
     // Prepare discover packet. Server should select first subnet for it
     Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
     sol->setRemoteAddr(IOAddress("192.0.2.1"));
@@ -2580,7 +2591,8 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectChange) {
     EXPECT_NE("0.0.0.0", addr.toText());
 
     // Get all subnets and use second subnet for verification
-    const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
+    const Subnet4Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
     ASSERT_EQ(2, subnets->size());
 
     // Advertised address must belong to the second pool (in subnet's range,
@@ -2979,6 +2991,8 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsORO) {
     comment_ = isc::config::parseAnswer(rcode_, x);
     ASSERT_EQ(0, rcode_);
 
+    CfgMgr::instance().commit();
+
     boost::shared_ptr<Pkt4> dis(new Pkt4(DHCPDISCOVER, 1234));
     // Set the giaddr and hops to non-zero address as if it was relayed.
     dis->setGiaddr(IOAddress("192.0.2.1"));
@@ -3195,7 +3209,8 @@ TEST_F(Dhcpv4SrvTest, relayOverride) {
     ASSERT_NO_THROW(configure(config));
 
     // Let's get the subnet configuration objects
-    const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
+    const Subnet4Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
     ASSERT_EQ(2, subnets->size());
 
     // Let's get them for easy reference
@@ -3270,7 +3285,8 @@ TEST_F(Dhcpv4SrvTest, relayOverrideAndClientClass) {
     // Use this config to set up the server
     ASSERT_NO_THROW(configure(config));
 
-    const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
+    const Subnet4Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
     ASSERT_EQ(2, subnets->size());
 
     // Let's get them for easy reference

+ 7 - 5
src/bin/dhcp4/tests/dhcp4_test_utils.cc

@@ -45,14 +45,14 @@ Dhcpv4SrvTest::Dhcpv4SrvTest()
     pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110")));
     subnet_->addPool(pool_);
 
-    CfgMgr::instance().clear();
-    CfgMgr::instance().deleteSubnets4();
-    CfgMgr::instance().addSubnet4(subnet_);
-
     // Add Router option.
     Option4AddrLstPtr opt_routers(new Option4AddrLst(DHO_ROUTERS));
     opt_routers->setAddress(IOAddress("192.0.2.2"));
     subnet_->getCfgOption()->add(opt_routers, false, "dhcp4");
+
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(subnet_);
+    CfgMgr::instance().commit();
 }
 
 Dhcpv4SrvTest::~Dhcpv4SrvTest() {
@@ -389,7 +389,7 @@ Dhcpv4SrvTest::createPacketFromBuffer(const Pkt4Ptr& src_pkt,
 
 void Dhcpv4SrvTest::TearDown() {
 
-    CfgMgr::instance().deleteSubnets4();
+    CfgMgr::instance().clear();
 
     // Close all open sockets.
     IfaceMgr::instance().closeSockets();
@@ -578,6 +578,8 @@ Dhcpv4SrvTest::configure(const std::string& config, NakedDhcpv4Srv& srv) {
     int rcode;
     ConstElementPtr comment = config::parseAnswer(rcode, status);
     ASSERT_EQ(0, rcode);
+
+    CfgMgr::instance().commit();
  }
 
 

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

@@ -17,6 +17,7 @@
 #include <dhcp/classify.h>
 #include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/cfg_subnets4.h>
 #include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcp4/json_config_parser.h>
@@ -225,8 +226,8 @@ TEST_F(DirectClientTest,  twoSubnets) {
     // Client should get an Offer (not a NAK).
     ASSERT_EQ(DHCPOFFER, response->getType());
     // Check that the offered address belongs to the suitable subnet.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(response->getYiaddr(),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->
+        getCfgSubnets4()->get(response->getYiaddr());
     ASSERT_TRUE(subnet);
     EXPECT_EQ("10.0.0.0", subnet->get().first.toText());
 
@@ -237,7 +238,8 @@ TEST_F(DirectClientTest,  twoSubnets) {
     // Client should get an Ack (not a NAK).
     ASSERT_EQ(DHCPACK, response->getType());
     // Check that the offered address belongs to the suitable subnet.
-    subnet = CfgMgr::instance().getSubnet4(response->getYiaddr(), classify_);
+    subnet = CfgMgr::instance().getCurrentCfg()->
+        getCfgSubnets4()->get(response->getYiaddr());
     ASSERT_TRUE(subnet);
     EXPECT_EQ("192.0.2.0", subnet->get().first.toText());
 
@@ -283,8 +285,8 @@ TEST_F(DirectClientTest, oneSubnet) {
     // an Offer message.
     ASSERT_EQ(DHCPOFFER, response->getType());
     // Check that the offered address belongs to the suitable subnet.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(response->getYiaddr(),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->
+        getCfgSubnets4()->get(response->getYiaddr());
     ASSERT_TRUE(subnet);
     EXPECT_EQ("10.0.0.0", subnet->get().first.toText());
 
@@ -302,8 +304,8 @@ TEST_F(DirectClientTest, renew) {
     ASSERT_NO_FATAL_FAILURE(configureSubnet("10.0.0.0"));
     // Make sure that the subnet has been really added. Also, the subnet
     // will be needed to create a lease for a client.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("10.0.0.10"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->
+        getCfgSubnets4()->get(IOAddress("10.0.0.10"));
     // Create a lease for a client that we will later renewed. By explicitly
     // creating a lease we will get to know the lease parameters, such as
     // leased address etc.
@@ -339,7 +341,8 @@ TEST_F(DirectClientTest, renew) {
 
     ASSERT_EQ(DHCPACK, response->getType());
     // Check that the offered address belongs to the suitable subnet.
-    subnet = CfgMgr::instance().getSubnet4(response->getYiaddr(), classify_);
+    subnet = CfgMgr::instance().getCurrentCfg()->
+        getCfgSubnets4()->get(response->getYiaddr());
     ASSERT_TRUE(subnet);
     EXPECT_EQ("10.0.0.0", subnet->get().first.toText());
 
@@ -360,8 +363,8 @@ TEST_F(DirectClientTest, rebind) {
     ASSERT_NO_FATAL_FAILURE(configureSubnet("10.0.0.0"));
     // Make sure that the subnet has been really added. Also, the subnet
     // will be needed to create a lease for a client.
-    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("10.0.0.10"),
-                                                      classify_);
+    Subnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->
+        getCfgSubnets4()->get(IOAddress("10.0.0.10"));
     // Create a lease, which will be later renewed. By explicitly creating a
     // lease we will know the lease parameters, such as leased address etc.
     const uint8_t hwaddr[] = { 1, 2, 3, 4, 5, 6 };
@@ -373,9 +376,9 @@ TEST_F(DirectClientTest, rebind) {
     LeaseMgrFactory::instance().addLease(lease);
 
     // Broadcast Request through an interface for which there is no subnet
-    // configured. This messag should be discarded by the server.
+    // configured. This message should be discarded by the server.
     Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
-    req->setCiaddr(IOAddress("10.0.0.10"));
+     req->setCiaddr(IOAddress("10.0.0.10"));
     req = createClientMessage(req, "eth1");
     req->setRemoteAddr(req->getCiaddr());
 
@@ -404,7 +407,8 @@ TEST_F(DirectClientTest, rebind) {
     // (transmitted over eth0).
     EXPECT_EQ(5678, response->getTransid());
     // Check that the offered address belongs to the suitable subnet.
-    subnet = CfgMgr::instance().getSubnet4(response->getYiaddr(), classify_);
+    subnet = CfgMgr::instance().getCurrentCfg()->
+        getCfgSubnets4()->get(response->getYiaddr());
     ASSERT_TRUE(subnet);
     EXPECT_EQ("10.0.0.0", subnet->get().first.toText());
 

+ 4 - 2
src/bin/dhcp4/tests/kea_controller_unittest.cc

@@ -118,7 +118,8 @@ TEST_F(JSONFileBackendTest, jsonFile) {
     EXPECT_NO_THROW(srv->init(TEST_FILE));
 
     // Now check if the configuration has been applied correctly.
-    const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
+    const Subnet4Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(3, subnets->size()); // We expect 3 subnets.
 
@@ -187,7 +188,8 @@ TEST_F(JSONFileBackendTest, comments) {
     EXPECT_NO_THROW(srv->init(TEST_FILE));
 
     // Now check if the configuration has been applied correctly.
-    const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
+    const Subnet4Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(1, subnets->size());
 

+ 23 - 15
src/lib/dhcpsrv/cfg_subnets4.cc

@@ -26,6 +26,12 @@ const IOAddress& ZERO_ADDRESS() {
     return (address);
 }
 
+/// @brief Returns @c IOAddress object holding broadcast address.
+const IOAddress& BCAST_ADDRESS() {
+    static IOAddress address("255.255.255.255");
+    return (address);
+}
+
 } // end of anonymous namespace
 
 namespace isc {
@@ -57,7 +63,7 @@ CfgSubnets4::get(const Selector& selector) const {
     // address will not match with any of the relay addresses accross all
     // subnets, but we need to verify that for all subnets before we can try
     // to use the giaddr to match with the subnet prefix.
-    if (selector.giaddr_.isSpecified() && selector.giaddr_ != ZERO_ADDRESS()) {
+    if (selector.giaddr_ != ZERO_ADDRESS()) {
         for (Subnet4Collection::const_iterator subnet = subnets_.begin();
              subnet != subnets_.end(); ++subnet) {
             // Eliminate those subnets that do not meet client class criteria.
@@ -79,36 +85,31 @@ CfgSubnets4::get(const Selector& selector) const {
 
     IOAddress address = ZERO_ADDRESS();
     // If there is a giaddr, use it for subnet selection.
-    if (selector.giaddr_.isSpecified() &&
-        (selector.giaddr_ != ZERO_ADDRESS())) {
+    if (selector.giaddr_ != ZERO_ADDRESS()) {
         address = selector.giaddr_;
 
     // If it is a Renew or Rebind, use the ciaddr.
-    } else if (selector.ciaddr_.isSpecified() &&
-               selector.ciaddr_ != ZERO_ADDRESS()) {
+    } else if ((selector.ciaddr_ != ZERO_ADDRESS()) &&
+               (selector.local_address_ != BCAST_ADDRESS())) {
         address = selector.ciaddr_;
 
     // If ciaddr is not specified, use the source address.
-    } else if (selector.remote_address_.isSpecified() &&
-               selector.remote_address_ != ZERO_ADDRESS()) {
+    } else if ((selector.remote_address_ != ZERO_ADDRESS()) &&
+               (selector.local_address_ != BCAST_ADDRESS())) {
         address = selector.remote_address_;
 
     // If local interface name is known, use the local address on this
     // interface.
-    } else if (selector.iface_name_.isSpecified()) {
+    } else if (!selector.iface_name_.empty()) {
         Iface* iface = IfaceMgr::instance().getIface(selector.iface_name_);
         // This should never happen in the real life. Hence we throw an
         // exception.
         if (iface == NULL) {
-            isc_throw(isc::BadValue, "interface " << selector.iface_name_.get()
+            isc_throw(isc::BadValue, "interface " << selector.iface_name_
                       << " doesn't exist and therefore it is impossible"
                       " to find a suitable subnet for its IPv4 address");
         }
         iface->getAddress4(address);
-
-    } else {
-        isc_throw(isc::BadValue, "subnet selector structure does not contain"
-                  " sufficient information");
     }
 
     // Unable to find a suitable address to use for subnet selection.
@@ -117,11 +118,18 @@ CfgSubnets4::get(const Selector& selector) const {
     }
 
     // We have identified an address in the client's packet that can be
-    // used for subnet selection. Match this packet with the subnets.
+    // used for subnet selection. Match this packet with the subnets. 
+    return (get(address, selector.client_classes_));
+}
+
+Subnet4Ptr
+CfgSubnets4::get(const IOAddress& address,
+                 const ClientClasses& client_classes) const {
     for (Subnet4Collection::const_iterator subnet = subnets_.begin();
          subnet != subnets_.end(); ++subnet) {
+
         // Eliminate those subnets that do not meet client class criteria.
-        if (!(*subnet)->clientSupported(selector.client_classes_)) {
+        if (!(*subnet)->clientSupported(client_classes)) {
             continue;
         }
 

+ 21 - 10
src/lib/dhcpsrv/cfg_subnets4.h

@@ -48,23 +48,20 @@ public:
     /// @brief Subnet selector used in @c CfgSubnets4::getSubnet4.
     ///
     /// This structure holds various parameters extracted from a packet sent
-    /// by a DHCP client used to select the subnet for the client. Note that
-    /// data members are optional which means that they may be left unspecified
-    /// by the caller, if the caller doesn't have access to the relevant
-    /// information.
+    /// by a DHCP client used to select the subnet for the client.
     struct Selector {
         /// @brief ciaddr from the client's message.
-        util::OptionalValue<asiolink::IOAddress> ciaddr_;
+        asiolink::IOAddress ciaddr_;
         /// @brief giaddr from the client's message.
-        util::OptionalValue<asiolink::IOAddress> giaddr_;
+        asiolink::IOAddress giaddr_;
         /// @brief Address on which the message was received.
-        util::OptionalValue<asiolink::IOAddress> local_address_;
+        asiolink::IOAddress local_address_;
         /// @brief Source address of the message.
-        util::OptionalValue<asiolink::IOAddress> remote_address_;
+        asiolink::IOAddress remote_address_;
         /// @brief Classes that the client belongs to.
-        util::OptionalValue<ClientClasses> client_classes_;
+        ClientClasses client_classes_;
         /// @brief Name of the interface on which the message was received.
-        util::OptionalValue<std::string> iface_name_;
+        std::string iface_name_;
 
         /// @brief Default constructor.
         ///
@@ -129,6 +126,20 @@ public:
     /// or they are insufficient to select a subnet.
     Subnet4Ptr get(const Selector& selector) const;
 
+    /// @brief Returns pointer to a subnet if provided address is in its range.
+    ///
+    /// This method returns a pointer to the subnet if the address passed in
+    /// parameter is in range with this subnet. This is mainly used for unit
+    /// testing. This method is also called by the @c get(Selector).
+    ///
+    /// @param address Address for which the subnet is searched.
+    /// @param client_classes Optional parameter specifying the classes that
+    /// the client belongs to.
+    ///
+    /// @return Pointer to the selected subnet or NULL if no subnet found.
+    Subnet4Ptr get(const asiolink::IOAddress& address,
+                   const ClientClasses& client_classes = ClientClasses()) const;
+
 private:
 
     /// @brief Checks that the IPv4 subnet with the given id already exists.

+ 0 - 83
src/lib/dhcpsrv/cfgmgr.cc

@@ -164,78 +164,6 @@ void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
     subnets6_.push_back(subnet);
 }
 
-Subnet4Ptr
-CfgMgr::getSubnet4(const isc::asiolink::IOAddress& hint,
-                   const isc::dhcp::ClientClasses& classes,
-                   bool relay) const {
-    // Iterate over existing subnets to find a suitable one for the
-    // given address.
-    for (Subnet4Collection::const_iterator subnet = subnets4_.begin();
-         subnet != subnets4_.end(); ++subnet) {
-
-        // If client is rejected because of not meeting client class criteria...
-        if (!(*subnet)->clientSupported(classes)) {
-            continue;
-        }
-
-        // If the hint is a relay address, and there is relay info specified
-        // for this subnet and those two match, then use this subnet.
-        if (relay && ((*subnet)->getRelayInfo().addr_ == hint) ) {
-            LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
-                      DHCPSRV_CFGMGR_SUBNET4_RELAY)
-                .arg((*subnet)->toText()).arg(hint.toText());
-            return (*subnet);
-        }
-
-        // Let's check if the client belongs to the given subnet
-        if ((*subnet)->inRange(hint)) {
-            LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
-                      DHCPSRV_CFGMGR_SUBNET4)
-                      .arg((*subnet)->toText()).arg(hint.toText());
-            return (*subnet);
-        }
-    }
-
-    // sorry, we don't support that subnet
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_NO_SUBNET4)
-              .arg(hint.toText());
-    return (Subnet4Ptr());
-}
-
-Subnet4Ptr
-CfgMgr::getSubnet4(const std::string& iface_name,
-                   const isc::dhcp::ClientClasses& classes) const {
-    Iface* iface = IfaceMgr::instance().getIface(iface_name);
-    // This should never happen in the real life. Hence we throw an exception.
-    if (iface == NULL) {
-        isc_throw(isc::BadValue, "interface " << iface_name <<
-                  " doesn't exist and therefore it is impossible"
-                  " to find a suitable subnet for its IPv4 address");
-    }
-    IOAddress addr("0.0.0.0");
-    // If IPv4 address assigned to the interface exists, find a suitable
-    // subnet for it, else return NULL pointer to indicate that no subnet
-    // could be found.
-    return (iface->getAddress4(addr) ? getSubnet4(addr, classes) : Subnet4Ptr());
-}
-
-void CfgMgr::addSubnet4(const Subnet4Ptr& subnet) {
-    /// @todo: Check that this new subnet does not cross boundaries of any
-    /// other already defined subnet.
-    if (isDuplicate(*subnet)) {
-        isc_throw(isc::dhcp::DuplicateSubnetID, "ID of the new IPv4 subnet '"
-                  << subnet->getID() << "' is already in use");
-    }
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_SUBNET4)
-              .arg(subnet->toText());
-    subnets4_.push_back(subnet);
-}
-
-void CfgMgr::deleteSubnets4() {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_DELETE_SUBNET4);
-    subnets4_.clear();
-}
-
 void CfgMgr::deleteSubnets6() {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_DELETE_SUBNET6);
     subnets6_.clear();
@@ -247,17 +175,6 @@ std::string CfgMgr::getDataDir() {
 }
 
 bool
-CfgMgr::isDuplicate(const Subnet4& subnet) const {
-    for (Subnet4Collection::const_iterator subnet_it = subnets4_.begin();
-         subnet_it != subnets4_.end(); ++subnet_it) {
-        if ((*subnet_it)->getID() == subnet.getID()) {
-            return (true);
-        }
-    }
-    return (false);
-}
-
-bool
 CfgMgr::isDuplicate(const Subnet6& subnet) const {
     for (Subnet6Collection::const_iterator subnet_it = subnets6_.begin();
          subnet_it != subnets6_.end(); ++subnet_it) {

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

@@ -215,16 +215,6 @@ public:
     /// completely new?
     void deleteSubnets6();
 
-    /// @brief Returns pointer to the collection of all IPv4 subnets.
-    ///
-    /// This is used in a hook (subnet4_select), where the hook is able
-    /// to choose a different subnet. Server code has to offer a list
-    /// of possible choices (i.e. all subnets).
-    /// @return a pointer to const Subnet4 collection
-    const Subnet4Collection* getSubnets4() const {
-        return (&subnets4_);
-    }
-
     /// @brief returns const reference to all subnets6
     ///
     /// This is used in a hook (subnet6_select), where the hook is able
@@ -235,63 +225,6 @@ public:
         return (&subnets6_);
     }
 
-    /// @brief get IPv4 subnet by address
-    ///
-    /// Finds a matching subnet, based on an address. This can be used
-    /// in two cases: when trying to find an appropriate lease based on
-    /// a) relay link address (that must be the address that is on link)
-    /// b) our global address on the interface the message was received on
-    ///    (for directly connected clients)
-    ///
-    /// If there are any classes specified in a subnet, that subnet
-    /// will be selected only if the client belongs to appropriate class.
-    ///
-    /// If relay is true then relay info overrides (i.e. value the sysadmin
-    /// can configure in Dhcp4/subnet4[X]/relay/ip-address) can be used.
-    /// That is true only for relays. Those overrides must not be used
-    /// for client address or for client hints. They are for giaddr only.
-    ///
-    /// @param hint an address that belongs to a searched subnet
-    /// @param classes classes the client belongs to
-    /// @param relay true if address specified in hint is a relay
-    ///
-    /// @return a subnet object
-    Subnet4Ptr getSubnet4(const isc::asiolink::IOAddress& hint,
-                          const isc::dhcp::ClientClasses& classes,
-                          bool relay = false) const;
-
-    /// @brief Returns a subnet for the specified local interface.
-    ///
-    /// This function checks that the IP address assigned to the specified
-    /// interface belongs to any IPv4 subnet configured, and returns this
-    /// subnet.
-    ///
-    /// @todo Implement classes support here.
-    ///
-    /// @param iface Short name of the interface which is being checked.
-    /// @param classes classes the client belongs to
-    ///
-    /// @return Pointer to the subnet matching interface specified or NULL
-    /// pointer if IPv4 address on the interface doesn't match any subnet.
-    Subnet4Ptr getSubnet4(const std::string& iface,
-                          const isc::dhcp::ClientClasses& classes) const;
-
-    /// @brief adds a subnet4
-    void addSubnet4(const Subnet4Ptr& subnet);
-
-    /// @brief removes all IPv4 subnets
-    ///
-    /// This method removes all existing IPv4 subnets. It is used during
-    /// reconfiguration - old configuration is wiped and new definitions
-    /// are used to recreate subnets.
-    ///
-    /// @todo Implement more intelligent approach. Note that comparison
-    /// between old and new configuration is tricky. For example: is
-    /// 192.0.2.0/23 and 192.0.2.0/24 the same subnet or is it something
-    /// completely new?
-    void deleteSubnets4();
-
-
     /// @brief returns path do the data directory
     ///
     /// This method returns a path to writeable directory that DHCP servers
@@ -484,14 +417,6 @@ protected:
     /// a match is found.
     Subnet6Collection subnets6_;
 
-    /// @brief A container for IPv4 subnets.
-    ///
-    /// That is a simple vector of pointers. It does not make much sense to
-    /// optimize access time (e.g. using a map), because typical search
-    /// pattern will use calling inRange() method on each subnet until
-    /// a match is found.
-    Subnet4Collection subnets4_;
-
 private:
 
     /// @brief Checks if current configuration is created and creates it if needed.
@@ -501,13 +426,6 @@ private:
     /// default current configuration.
     void ensureCurrentAllocated();
 
-    /// @brief Checks that the IPv4 subnet with the given id already exists.
-    ///
-    /// @param subnet Subnet for which this function will check if the other
-    /// subnet with equal id already exists.
-    /// @return true if the duplicate subnet exists.
-    bool isDuplicate(const Subnet4& subnet) const;
-
     /// @brief Checks that the IPv6 subnet with the given id already exists.
     ///
     /// @param subnet Subnet for which this function will check if the other

+ 0 - 4
src/lib/dhcpsrv/dhcpsrv_messages.mes

@@ -83,10 +83,6 @@ of active interfaces. This doesn't prevent the server from listening to
 the DHCP traffic through open sockets, but will rather be used by Interface
 Manager to select active interfaces when sockets are re-opened.
 
-% DHCPSRV_CFGMGR_DELETE_SUBNET4 deleting all IPv4 subnets
-A debug message noting that the DHCP configuration manager has deleted all IPv4
-subnets in its database.
-
 % DHCPSRV_CFGMGR_DELETE_SUBNET6 deleting all IPv6 subnets
 A debug message noting that the DHCP configuration manager has deleted all IPv6
 subnets in its database.

+ 1 - 1
src/lib/dhcpsrv/srv_config.cc

@@ -39,7 +39,7 @@ SrvConfig::getConfigSummary(const uint32_t selection) const {
     std::ostringstream s;
     size_t subnets_num;
     if ((selection & CFGSEL_SUBNET4) == CFGSEL_SUBNET4) {
-        subnets_num = CfgMgr::instance().getSubnets4()->size();
+        subnets_num = getCfgSubnets4()->getAll()->size();
         if (subnets_num > 0) {
             s << "added IPv4 subnets: " << subnets_num;
         } else {

+ 12 - 7
src/lib/dhcpsrv/tests/alloc_engine_unittest.cc

@@ -422,7 +422,8 @@ public:
         pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"),
                                    IOAddress("192.0.2.109")));
         subnet_->addPool(pool_);
-        cfg_mgr.addSubnet4(subnet_);
+        cfg_mgr.getStagingCfg()->getCfgSubnets4()->add(subnet_);
+        cfg_mgr.commit();
 
         factory_.create("type=memfile universe=4 persist=false");
     }
@@ -1319,13 +1320,15 @@ TEST_F(AllocEngine4Test, smallPool4) {
 
     IOAddress addr("192.0.2.17");
     CfgMgr& cfg_mgr = CfgMgr::instance();
-    cfg_mgr.deleteSubnets4(); // Get rid of the default test configuration
+
+    // Get rid of the default subnet configuration.
+    cfg_mgr.clear();
 
     // Create configuration similar to other tests, but with a single address pool
     subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
     pool_ = Pool4Ptr(new Pool4(addr, addr)); // just a single address
     subnet_->addPool(pool_);
-    cfg_mgr.addSubnet4(subnet_);
+    cfg_mgr.getStagingCfg()->getCfgSubnets4()->add(subnet_);
 
     Lease4Ptr lease = engine->allocateLease4(subnet_, clientid_, hwaddr_,
                                                IOAddress("0.0.0.0"),
@@ -1362,13 +1365,14 @@ TEST_F(AllocEngine4Test, outOfAddresses4) {
 
     IOAddress addr("192.0.2.17");
     CfgMgr& cfg_mgr = CfgMgr::instance();
-    cfg_mgr.deleteSubnets4(); // Get rid of the default test configuration
+    // Get rid of the default test configuration.
+    cfg_mgr.clear();
 
     // Create configuration similar to other tests, but with a single address pool
     subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
     pool_ = Pool4Ptr(new Pool4(addr, addr)); // just a single address
     subnet_->addPool(pool_);
-    cfg_mgr.addSubnet4(subnet_);
+    cfg_mgr.getStagingCfg()->getCfgSubnets4()->add(subnet_);
 
     // Just a different hw/client-id for the second client
     uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
@@ -1401,13 +1405,14 @@ TEST_F(AllocEngine4Test, discoverReuseExpiredLease4) {
 
     IOAddress addr("192.0.2.15");
     CfgMgr& cfg_mgr = CfgMgr::instance();
-    cfg_mgr.deleteSubnets4(); // Get rid of the default test configuration
+    // Get rid of the default test configuration.
+    cfg_mgr.clear();
 
     // Create configuration similar to other tests, but with a single address pool
     subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
     pool_ = Pool4Ptr(new Pool4(addr, addr)); // just a single address
     subnet_->addPool(pool_);
-    cfg_mgr.addSubnet4(subnet_);
+    cfg_mgr.getStagingCfg()->getCfgSubnets4()->add(subnet_);
 
     // Just a different hw/client-id for the second client
     uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};

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

@@ -282,7 +282,6 @@ public:
 
     void clear() {
         CfgMgr::instance().setVerbose(false);
-        CfgMgr::instance().deleteSubnets4();
         CfgMgr::instance().deleteSubnets6();
         CfgMgr::instance().clear();
     }
@@ -304,133 +303,6 @@ TEST_F(CfgMgrTest, configuration) {
     EXPECT_TRUE(configuration->getLoggingInfo().empty());
 }
 
-// This test verifies if the configuration manager is able to hold and return
-// valid subnets.
-TEST_F(CfgMgrTest, subnet4) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
-    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
-    Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));
-
-    // There shouldn't be any subnet configured at this stage
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.0"), classify_));
-
-    cfg_mgr.addSubnet4(subnet1);
-
-    // Now we have only one subnet, any request will be served from it
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.63"),
-                  classify_));
-
-    // Now we add more subnets and check that both old and new subnets
-    // are accessible.
-    cfg_mgr.addSubnet4(subnet2);
-    cfg_mgr.addSubnet4(subnet3);
-
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet4(IOAddress("192.0.2.191"), classify_));
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.15"), classify_));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("192.0.2.85"), classify_));
-
-    // Try to find an address that does not belong to any subnet
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.192"), classify_));
-
-    // Check that deletion of the subnets works.
-    cfg_mgr.deleteSubnets4();
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.191"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.15"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.85"), classify_));
-}
-
-// This test verifies if the configuration manager is able to hold subnets with
-// their classifier information and return proper subnets, based on those
-// classes.
-TEST_F(CfgMgrTest, classifySubnet4) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    // Let's configure 3 subnets
-    Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
-    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
-    Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));
-
-    cfg_mgr.addSubnet4(subnet1);
-    cfg_mgr.addSubnet4(subnet2);
-    cfg_mgr.addSubnet4(subnet3);
-
-    // Let's sanity check that we can use that configuration.
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.5"), classify_));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("192.0.2.70"), classify_));
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet4(IOAddress("192.0.2.130"), classify_));
-
-    // Client now belongs to bar class.
-    classify_.insert("bar");
-
-    // There are no class restrictions defined, so everything should work
-    // as before
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.5"), classify_));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("192.0.2.70"), classify_));
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet4(IOAddress("192.0.2.130"), classify_));
-
-    // Now let's add client class restrictions.
-    subnet1->allowClientClass("foo"); // Serve here only clients from foo class
-    subnet2->allowClientClass("bar"); // Serve here only clients from bar class
-    subnet3->allowClientClass("baz"); // Serve here only clients from baz class
-
-    // The same check as above should result in client being served only in
-    // bar class, i.e. subnet2
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.5"), classify_));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("192.0.2.70"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.130"), classify_));
-
-    // Now let's check that client with wrong class is not supported
-    classify_.clear();
-    classify_.insert("some_other_class");
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.5"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.70"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.130"), classify_));
-
-    // Finally, let's check that client without any classes is not supported
-    classify_.clear();
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.5"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.70"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.130"), classify_));
-}
-
-// This test verifies if the configuration manager is able to hold v4 subnets
-// with their relay address information and return proper subnets, based on
-// those addresses.
-TEST_F(CfgMgrTest, subnet4RelayOverride) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    // Let's configure 3 subnets
-    Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
-    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
-    Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));
-
-    cfg_mgr.addSubnet4(subnet1);
-    cfg_mgr.addSubnet4(subnet2);
-    cfg_mgr.addSubnet4(subnet3);
-
-    // Check that without relay-info specified, subnets are not selected
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("10.0.0.1"), classify_, true));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("10.0.0.2"), classify_, true));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("10.0.0.3"), classify_, true));
-
-    // Now specify relay info
-    subnet1->setRelayInfo(IOAddress("10.0.0.1"));
-    subnet2->setRelayInfo(IOAddress("10.0.0.2"));
-    subnet3->setRelayInfo(IOAddress("10.0.0.3"));
-
-    // And try again. This time relay-info is there and should match.
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("10.0.0.1"), classify_, true));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("10.0.0.2"), classify_, true));
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet4(IOAddress("10.0.0.3"), classify_, true));
-
-    // Finally, check that the relay works only if hint provided is relay address
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("10.0.0.1"), classify_, false));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("10.0.0.2"), classify_, false));
-    EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("10.0.0.3"), classify_, false));
-}
-
 // This test verifies if the configuration manager is able to hold v6 subnets
 // with their relay address information and return proper subnets, based on
 // those addresses.
@@ -858,63 +730,6 @@ TEST_F(CfgMgrTest, d2ClientConfig) {
     EXPECT_NE(*original_config, *updated_config);
 }
 
-// This test verfies that CfgMgr correctly determines that the address of the
-// interface belongs to existing IPv4 subnet.
-TEST_F(CfgMgrTest, getSubnet4ForInterface) {
-    IfaceMgrTestConfig config(true);
-
-    // Initially, there are no subnets configured, so none of the IPv4
-    // addresses assigned to eth0 and eth1 can match with any subnet.
-    EXPECT_FALSE(CfgMgr::instance().getSubnet4("eth0", classify_));
-    EXPECT_FALSE(CfgMgr::instance().getSubnet4("eth1", classify_));
-
-    // Configure first subnet which address on eth0 corresponds to.
-    Subnet4Ptr subnet1(new Subnet4(IOAddress("10.0.0.1"), 24, 1, 2, 3));
-    CfgMgr::instance().addSubnet4(subnet1);
-
-    // The address on eth0 should match the existing subnet.
-    Subnet4Ptr subnet1_ret;
-    subnet1_ret = CfgMgr::instance().getSubnet4("eth0", classify_);
-    ASSERT_TRUE(subnet1_ret);
-    EXPECT_EQ(subnet1->get().first, subnet1_ret->get().first);
-    // There should still be no match for eth1.
-    EXPECT_FALSE(CfgMgr::instance().getSubnet4("eth1", classify_));
-
-    // Configure a second subnet.
-    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.1"), 24, 1, 2, 3));
-    CfgMgr::instance().addSubnet4(subnet2);
-
-    // There should be match between eth0 and subnet1 and between eth1 and
-    // subnet 2.
-    subnet1_ret = CfgMgr::instance().getSubnet4("eth0", classify_);
-    ASSERT_TRUE(subnet1_ret);
-    EXPECT_EQ(subnet1->get().first, subnet1_ret->get().first);
-    Subnet4Ptr subnet2_ret = CfgMgr::instance().getSubnet4("eth1", classify_);
-    ASSERT_TRUE(subnet2_ret);
-    EXPECT_EQ(subnet2->get().first, subnet2_ret->get().first);
-
-    // This function throws an exception if the name of the interface is wrong.
-    EXPECT_THROW(CfgMgr::instance().getSubnet4("bogus-interface", classify_),
-                 isc::BadValue);
-
-}
-
-// Checks that detection of duplicated subnet IDs works as expected. It should
-// not be possible to add two IPv4 subnets holding the same ID to the config
-// manager.
-TEST_F(CfgMgrTest, subnet4Duplication) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3, 123));
-    Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3, 124));
-    Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3, 123));
-
-    ASSERT_NO_THROW(cfg_mgr.addSubnet4(subnet1));
-    EXPECT_NO_THROW(cfg_mgr.addSubnet4(subnet2));
-    // Subnet 3 has the same ID as subnet 1. It shouldn't be able to add it.
-    EXPECT_THROW(cfg_mgr.addSubnet4(subnet3), isc::dhcp::DuplicateSubnetID);
-}
-
 // Checks that detection of duplicated subnet IDs works as expected. It should
 // not be possible to add two IPv6 subnets holding the same ID to the config
 // manager.

+ 1 - 1
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc

@@ -446,7 +446,7 @@ public:
     /// during a given test if needed.
     void reset_context(){
         // Note set context universe to V6 as it has to be something.
-        CfgMgr::instance().deleteSubnets4();
+        CfgMgr::instance().clear();
         CfgMgr::instance().deleteSubnets6();
         parser_context_.reset(new ParserContext(Option::V6));
 

+ 1 - 7
src/lib/dhcpsrv/tests/srv_config_unittest.cc

@@ -137,7 +137,7 @@ SrvConfigTest::addSubnet4(const unsigned int index) {
         FAIL() << "Subnet index " << index << "out of range (0.."
                << TEST_SUBNETS_NUM << "): " << "unable to add IPv4 subnet";
     }
-    CfgMgr::instance().addSubnet4(test_subnets4_[index]);
+    conf_.getCfgSubnets4()->add(test_subnets4_[index]);
 }
 
 void
@@ -151,7 +151,6 @@ SrvConfigTest::addSubnet6(const unsigned int index) {
 
 void
 SrvConfigTest::clearSubnets() {
-    CfgMgr::instance().deleteSubnets4();
     CfgMgr::instance().deleteSubnets6();
 }
 
@@ -254,11 +253,6 @@ TEST_F(SrvConfigTest, summarySubnets) {
     EXPECT_EQ("added IPv4 subnets: 2; added IPv6 subnets: 2",
               conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET));
 
-    // Remove all subnets and make sure that there are no reported subnets
-    // back again.
-    clearSubnets();
-    EXPECT_EQ("no IPv4 subnets!; no IPv6 subnets!",
-              conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET));
 }
 
 // This test checks if entire configuration can be copied and that the sequence