Browse Source

[3625] Use CfgSubnets6 to obtain subnet information.

Marcin Siodelski 10 years ago
parent
commit
4a5895b993

+ 20 - 35
src/bin/dhcp6/dhcp6_srv.cc

@@ -38,6 +38,7 @@
 #include <dhcpsrv/lease_mgr.h>
 #include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/subnet.h>
+#include <dhcpsrv/subnet_selector.h>
 #include <dhcpsrv/utils.h>
 #include <exceptions/exceptions.h>
 #include <hooks/callout_handle.h>
@@ -868,42 +869,24 @@ Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
 
 Subnet6Ptr
 Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
+    // Initialize subnet selector with the values used to select the subnet.
+    SubnetSelector selector;
+    selector.iface_name_ = question->getIface();
+    selector.remote_address_ = question->getRemoteAddr();
+    selector.first_relay_linkaddr_ = IOAddress("::");
+    selector.client_classes_ = question->classes_;
+
+    // Initialize fields specific to relayed messages.
+    if (!question->relay_info_.empty()) {
+        selector.first_relay_linkaddr_ = question->relay_info_.back().linkaddr_;
+        selector.interface_id_ =
+            question->getAnyRelayOption(D6O_INTERFACE_ID,
+                                        Pkt6::RELAY_GET_FIRST);
+    }
 
-    Subnet6Ptr subnet;
-
-    if (question->relay_info_.empty()) {
-        // This is a direct (non-relayed) message
-
-        // Try to find a subnet if received packet from a directly connected client
-        subnet = CfgMgr::instance().getSubnet6(question->getIface(),
-                                               question->classes_);
-        if (!subnet) {
-            // If no subnet was found, try to find it based on remote address
-            subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr(),
-                                                   question->classes_);
-        }
-    } else {
-
-        // This is a relayed message
-        OptionPtr interface_id = question->getAnyRelayOption(D6O_INTERFACE_ID,
-                                                             Pkt6::RELAY_GET_FIRST);
-        if (interface_id) {
-            subnet = CfgMgr::instance().getSubnet6(interface_id,
-                                                   question->classes_);
-        }
-
-        if (!subnet) {
-            // If no interface-id was specified (or not configured on server),
-            // let's try address matching
-            IOAddress link_addr = question->relay_info_.back().linkaddr_;
+    Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()->
+        getCfgSubnets6()->selectSubnet(selector);
 
-            // if relay filled in link_addr field, then let's use it
-            if (link_addr != IOAddress("::")) {
-                subnet = CfgMgr::instance().getSubnet6(link_addr,
-                                                       question->classes_, true);
-            }
-        }
-    }
 
     // Let's execute all callouts registered for subnet6_receive
     if (HooksManager::calloutsPresent(Hooks.hook_index_subnet6_select_)) {
@@ -919,7 +902,9 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
         // We pass pointer to const collection for performance reasons.
         // Otherwise we would get a non-trivial performance penalty each
         // time subnet6_select is called.
-        callout_handle->setArgument("subnet6collection", CfgMgr::instance().getSubnets6());
+        callout_handle->setArgument("subnet6collection",
+                                    CfgMgr::instance().getCurrentCfg()->
+                                    getCfgSubnets6()->getAll());
 
         // Call user (and server-side) callouts
         HooksManager::callCallouts(Hooks.hook_index_subnet6_select_, *callout_handle);

+ 1 - 7
src/bin/dhcp6/json_config_parser.cc

@@ -344,7 +344,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().addSubnet6(sub6ptr);
+                CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(sub6ptr);
             } catch (const std::exception& ex) {
                 isc_throw(DhcpConfigError, ex.what() << " ("
                           << subnet->getPosition() << ")");
@@ -534,12 +534,6 @@ public:
     ///
     /// @param subnets_list pointer to a list of IPv6 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
-        isc::dhcp::CfgMgr::instance().deleteSubnets6();
-
         BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
             ParserPtr parser(new Subnet6ConfigParser("subnet"));
             parser->build(subnet);

+ 77 - 55
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -26,6 +26,7 @@
 #include <dhcpsrv/addr_utilities.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/subnet.h>
+#include <dhcpsrv/subnet_selector.h>
 #include <dhcpsrv/testutils/config_result_check.h>
 #include <hooks/hooks_manager.h>
 
@@ -247,13 +248,13 @@ public:
     getOptionFromSubnet(const IOAddress& subnet_address,
                         const uint16_t option_code,
                         const uint16_t expected_options_count = 1) {
-        Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(subnet_address,
-                                                          classify_);
+        Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+            selectSubnet(subnet_address, classify_);
         if (!subnet) {
             /// @todo replace toText() with the use of operator <<.
             ADD_FAILURE() << "A subnet for the specified address "
                           << subnet_address.toText()
-                          << "does not exist in Config Manager";
+                          << " does not exist in Config Manager";
         }
         OptionContainerPtr options =
             subnet->getCfgOption()->getAll("dhcp6");
@@ -469,6 +470,8 @@ public:
                            const uint16_t option_code,
                            const uint8_t* expected_data,
                            const size_t expected_data_len) {
+        CfgMgr::instance().clear();
+
         std::string config = createConfigWithOption(params);
         ASSERT_TRUE(executeConfiguration(config, "parse option configuration"));
 
@@ -557,8 +560,8 @@ TEST_F(Dhcp6ParserTest, subnetGlobalDefaults) {
 
     // Now check if the configuration was indeed handled and we have
     // expected pool configured.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-        classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
     EXPECT_EQ(1000, subnet->getT1());
     EXPECT_EQ(2000, subnet->getT2());
@@ -605,7 +608,10 @@ TEST_F(Dhcp6ParserTest, multipleSubnets) {
         EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
         checkResult(x, 0);
 
-        const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+        CfgMgr::instance().commit();
+
+        const Subnet6Collection* subnets =
+            CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
         ASSERT_TRUE(subnets);
         ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
 
@@ -660,7 +666,10 @@ TEST_F(Dhcp6ParserTest, multipleSubnetsExplicitIDs) {
         EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
         checkResult(x, 0);
 
-        const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+        CfgMgr::instance().commit();
+
+        const Subnet6Collection* subnets =
+            CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
         ASSERT_TRUE(subnets);
         ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
 
@@ -796,7 +805,10 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) {
     EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
     checkResult(x, 0);
 
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    CfgMgr::instance().commit();
+
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
 
@@ -805,7 +817,9 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) {
     EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
     checkResult(x, 0);
 
-    subnets = CfgMgr::instance().getSubnets6();
+    CfgMgr::instance().commit();
+
+    subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(3, subnets->size()); // We expect 3 subnets now (4th is removed)
 
@@ -820,12 +834,16 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) {
     EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
     checkResult(x, 0);
 
+    CfgMgr::instance().commit();
+
     // Do reconfiguration
     json = Element::fromJSON(config_second_removed);
     EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
     checkResult(x, 0);
 
-    subnets = CfgMgr::instance().getSubnets6();
+    CfgMgr::instance().commit();
+
+    subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(3, subnets->size()); // We expect 4 subnets
 
@@ -863,8 +881,8 @@ TEST_F(Dhcp6ParserTest, subnetLocal) {
     // returned value should be 0 (configuration success)
     checkResult(status, 0);
 
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
     EXPECT_EQ(1, subnet->getT1());
     EXPECT_EQ(2, subnet->getT2());
@@ -898,8 +916,8 @@ TEST_F(Dhcp6ParserTest, subnetInterface) {
     // returned value should be 0 (configuration success)
     checkResult(status, 0);
 
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
     EXPECT_EQ(valid_iface_, subnet->getIface());
 }
@@ -931,8 +949,8 @@ TEST_F(Dhcp6ParserTest, subnetInterfaceBogus) {
     checkResult(status, 1);
     EXPECT_TRUE(errorContainsPosition(status, "<string>"));
 
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     EXPECT_FALSE(subnet);
 }
 
@@ -993,16 +1011,20 @@ TEST_F(Dhcp6ParserTest, subnetInterfaceId) {
 
     // Try to get a subnet based on bogus interface-id option
     OptionBuffer tmp(bogus_interface_id.begin(), bogus_interface_id.end());
-    OptionPtr ifaceid(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(ifaceid, classify_);
+    SubnetSelector selector;
+    selector.first_relay_linkaddr_ = IOAddress("5000::1");
+    selector.interface_id_.reset(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(selector);
     EXPECT_FALSE(subnet);
 
     // Now try to get subnet for valid interface-id value
     tmp = OptionBuffer(valid_interface_id.begin(), valid_interface_id.end());
-    ifaceid.reset(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
-    subnet = CfgMgr::instance().getSubnet6(ifaceid, classify_);
+    selector.interface_id_.reset(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
+    subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(selector);
     ASSERT_TRUE(subnet);
-    EXPECT_TRUE(ifaceid->equals(subnet->getInterfaceId()));
+    EXPECT_TRUE(selector.interface_id_->equals(subnet->getInterfaceId()));
 }
 
 
@@ -1084,7 +1106,8 @@ TEST_F(Dhcp6ParserTest, multiplePools) {
     ASSERT_NO_THROW(status = configureDhcp6Server(srv_, json));
     checkResult(status, 0);
 
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(2, subnets->size()); // We expect 2 subnets
 
@@ -1163,8 +1186,8 @@ TEST_F(Dhcp6ParserTest, poolPrefixLen) {
     // returned value must be 1 (configuration parse error)
     checkResult(x, 0);
 
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
     EXPECT_EQ(1000, subnet->getT1());
     EXPECT_EQ(2000, subnet->getT2());
@@ -1205,8 +1228,8 @@ TEST_F(Dhcp6ParserTest, pdPoolBasics) {
     checkResult(x, 0);
 
     // Test that we can retrieve the subnet.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
 
     // Fetch the collection of PD pools.  It should have 1 entry.
@@ -1277,8 +1300,8 @@ TEST_F(Dhcp6ParserTest, pdPoolList) {
     checkResult(x, 0);
 
     // Test that we can retrieve the subnet.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
 
     // Fetch the collection of NA pools.  It should have 1 entry.
@@ -1333,8 +1356,8 @@ TEST_F(Dhcp6ParserTest, subnetAndPrefixDelegated) {
     checkResult(x, 0);
 
     // Test that we can retrieve the subnet.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
 
     ASSERT_TRUE(subnet);
 
@@ -2027,8 +2050,8 @@ TEST_F(Dhcp6ParserTest, optionDataDefaults) {
     EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
     checkResult(x, 0);
 
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
     OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp6");
     ASSERT_EQ(2, options->size());
@@ -2122,8 +2145,8 @@ TEST_F(Dhcp6ParserTest, optionDataTwoSpaces) {
     checkResult(status, 0);
 
     // Options should be now available for the subnet.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
     // Try to get the option from the space dhcp6.
     OptionDescriptor desc1 = subnet->getCfgOption()->get("dhcp6", 38);
@@ -2278,8 +2301,8 @@ TEST_F(Dhcp6ParserTest, optionDataEncapsulate) {
     checkResult(status, 0);
 
     // Get the subnet.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
 
     // We should have one option available.
@@ -2341,8 +2364,8 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
     EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
     checkResult(x, 0);
 
-    Subnet6Ptr subnet1 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                       classify_);
+    Subnet6Ptr subnet1 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet1);
     OptionContainerPtr options1 = subnet1->getCfgOption()->getAll("dhcp6");
     ASSERT_EQ(1, options1->size());
@@ -2367,8 +2390,8 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
                sizeof(subid_expected));
 
     // Test another subnet in the same way.
-    Subnet6Ptr subnet2 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:2::4"),
-                                                       classify_);
+    Subnet6Ptr subnet2 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:2::4"), classify_);
     ASSERT_TRUE(subnet2);
     OptionContainerPtr options2 = subnet2->getCfgOption()->getAll("dhcp6");
     ASSERT_EQ(1, options2->size());
@@ -2402,8 +2425,6 @@ TEST_F(Dhcp6ParserTest, optionDataBoolean) {
     ASSERT_TRUE(executeConfiguration(config, "parse configuration with a"
                                      " boolean value"));
 
-    CfgMgr::instance().commit();
-
     // The subnet should now hold one option with the code 1000.
     OptionDescriptor desc =
         getOptionFromSubnet(IOAddress("2001:db8:1::5"), 1000);
@@ -2538,8 +2559,8 @@ TEST_F(Dhcp6ParserTest, optionDataLowerCase) {
     EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
     checkResult(x, 0);
 
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
     OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp6");
     ASSERT_EQ(1, options->size());
@@ -2581,8 +2602,8 @@ TEST_F(Dhcp6ParserTest, stdOptionData) {
     EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
     checkResult(x, 0);
 
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
     OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp6");
     ASSERT_EQ(1, options->size());
@@ -2659,8 +2680,8 @@ TEST_F(Dhcp6ParserTest, vendorOptionsHex) {
     checkResult(status, 0);
 
     // Options should be now available for the subnet.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
 
     // Try to get the option from the vendor space 4491
@@ -2721,8 +2742,8 @@ TEST_F(Dhcp6ParserTest, vendorOptionsCsv) {
     checkResult(status, 0);
 
     // Options should be now available for the subnet.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
 
     // Try to get the option from the vendor space 4491
@@ -2864,8 +2885,8 @@ TEST_F(Dhcp6ParserTest, DISABLED_stdOptionDataEncapsulate) {
     checkResult(status, 0);
 
     // Get the subnet.
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::5"), classify_);
     ASSERT_TRUE(subnet);
 
     // We should have one option available.
@@ -3151,8 +3172,8 @@ TEST_F(Dhcp6ParserTest, subnetRelayInfo) {
     // returned value should be 0 (configuration success)
     checkResult(status, 0);
 
-    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::1"),
-                                                      classify_);
+    Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+        selectSubnet(IOAddress("2001:db8:1::1"), classify_);
     ASSERT_TRUE(subnet);
     EXPECT_EQ("2001:db8:1::abcd", subnet->getRelayInfo().addr_.toText());
 }
@@ -3191,7 +3212,8 @@ TEST_F(Dhcp6ParserTest, classifySubnets) {
     EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
     checkResult(x, 0);
 
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
 

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

@@ -233,7 +233,8 @@ TEST_F(ConfirmTest, relayedClientNoAddress) {
     // Configure the server.
     configure(CONFIRM_CONFIGS[1], *client.getServer());
     // Make sure we ended-up having expected number of subnets configured.
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
     ASSERT_EQ(2, subnets->size());
     // Client to send relayed message.
     client.useRelay();
@@ -255,7 +256,7 @@ TEST_F(ConfirmTest, relayedClientNoSubnet) {
     ASSERT_NO_FATAL_FAILURE(requestLease(CONFIRM_CONFIGS[1], 2, client));
     // Now that the client has a lease, let's remove any subnets to check
     // how the server would respond to the Confirm.
-    ASSERT_NO_THROW(CfgMgr::instance().deleteSubnets6());
+    ASSERT_NO_THROW(CfgMgr::instance().clear());
     // Send Confirm message to the server.
     ASSERT_NO_THROW(client.doConfirm());
     // Client should have received a status code option and this option should

+ 4 - 3
src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc

@@ -182,7 +182,7 @@ TEST_F(CtrlDhcpv6SrvTest, configReload) {
     ElementPtr config = Element::fromJSON(config_txt);
 
     // Make sure there are no subnets configured.
-    CfgMgr::instance().deleteSubnets6();
+    CfgMgr::instance().clear();
 
     // Now send the command
     int rcode = -1;
@@ -192,11 +192,12 @@ TEST_F(CtrlDhcpv6SrvTest, configReload) {
     EXPECT_EQ(0, rcode); // Expect success
 
     // Check that the config was indeed applied.
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll();
     EXPECT_EQ(3, subnets->size());
 
     // Clean up after the test.
-    CfgMgr::instance().deleteSubnets6();
+    CfgMgr::instance().clear();
 }
 
 } // End of anonymous namespace

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

@@ -128,6 +128,7 @@ Dhcp6SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
 
 void
 Dhcp6SrvD2Test::configure(const std::string& config, bool exp_result) {
+    CfgMgr::instance().clear();
     ElementPtr json = Element::fromJSON(config);
     ConstElementPtr status;
 

+ 4 - 3
src/bin/dhcp6/tests/dhcp6_message_test.cc

@@ -53,7 +53,8 @@ Dhcpv6MessageTest::requestLease(const std::string& config,
     // Configure the server.
     configure(config, *client.getServer());
     // Make sure we ended-up having expected number of subnets configured.
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
     ASSERT_EQ(subnets_num, subnets->size());
     // Do the actual 4-way exchange.
     ASSERT_NO_THROW(client.doSARR());
@@ -63,8 +64,8 @@ Dhcpv6MessageTest::requestLease(const std::string& config,
     // subnets.
     ASSERT_EQ(1, client.getLeaseNum());
     Lease6 lease_client = client.getLease(0);
-    ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client.addr_,
-                                              ClientClasses()));
+    ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
+                selectSubnet(lease_client.addr_, ClientClasses()));
     // Check that the client's lease matches the information on the server
     // side.
     Lease6Ptr lease_server = checkLease(lease_client);

+ 65 - 48
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -1182,8 +1182,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
 
     // CASE 1: We have only one subnet defined and we received local traffic.
     // The only available subnet used to be picked, but not anymore
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
+    CfgMgr::instance().commit();
 
     Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     pkt->setRemoteAddr(IOAddress("fe80::abcd"));
@@ -1196,38 +1197,42 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
     // We should NOT select it.
 
     // Identical steps as in case 1, but repeated for clarity
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
+    CfgMgr::instance().commit();
     pkt->setRemoteAddr(IOAddress("2001:db8:abcd::2345"));
     Subnet6Ptr selected = srv.selectSubnet(pkt);
     EXPECT_FALSE(selected);
 
     // CASE 3: We have three subnets defined and we received local traffic.
     // Nothing should be selected.
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1);
-    CfgMgr::instance().addSubnet6(subnet2);
-    CfgMgr::instance().addSubnet6(subnet3);
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
+    CfgMgr::instance().commit();
     pkt->setRemoteAddr(IOAddress("fe80::abcd"));
     selected = srv.selectSubnet(pkt);
     EXPECT_FALSE(selected);
 
     // CASE 4: We have three subnets defined and we received relayed traffic
     // that came out of subnet 2. We should select subnet2 then
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1);
-    CfgMgr::instance().addSubnet6(subnet2);
-    CfgMgr::instance().addSubnet6(subnet3);
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
+    CfgMgr::instance().commit();
     pkt->setRemoteAddr(IOAddress("2001:db8:2::baca"));
     selected = srv.selectSubnet(pkt);
     EXPECT_EQ(selected, subnet2);
 
     // CASE 5: We have three subnets defined and we received relayed traffic
     // that came out of undefined subnet. We should select nothing
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1);
-    CfgMgr::instance().addSubnet6(subnet2);
-    CfgMgr::instance().addSubnet6(subnet3);
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
+    CfgMgr::instance().commit();
     pkt->setRemoteAddr(IOAddress("2001:db8:4::baca"));
     EXPECT_FALSE(srv.selectSubnet(pkt));
 }
@@ -1246,8 +1251,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
 
     // CASE 1: We have only one subnet defined and it is available via eth0.
     // Packet came from eth0. The only available subnet should be selected
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
+    CfgMgr::instance().commit();
 
     Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     pkt->setIface("eth0");
@@ -1257,8 +1263,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
 
     // CASE 2: We have only one subnet defined and it is available via eth0.
     // Packet came from eth1. We should not select it
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
+    CfgMgr::instance().commit();
 
     pkt->setIface("eth1");
 
@@ -1268,10 +1275,11 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
     // CASE 3: We have only 3 subnets defined, one over eth0, one remote and
     // one over wifi1.
     // Packet came from eth1. We should not select it
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1);
-    CfgMgr::instance().addSubnet6(subnet2);
-    CfgMgr::instance().addSubnet6(subnet3);
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
+    CfgMgr::instance().commit();
 
     pkt->setIface("eth0");
     EXPECT_EQ(subnet1, srv.selectSubnet(pkt));
@@ -1298,8 +1306,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
 
     // CASE 1: We have only one subnet defined and we received relayed traffic.
     // The only available subnet should NOT be selected.
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
+    CfgMgr::instance().commit();
 
     Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     pkt->relay_info_.push_back(relay);
@@ -1309,19 +1318,21 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
 
     // CASE 2: We have three subnets defined and we received relayed traffic.
     // Nothing should be selected.
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1);
-    CfgMgr::instance().addSubnet6(subnet2);
-    CfgMgr::instance().addSubnet6(subnet3);
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
+    CfgMgr::instance().commit();
     selected = srv.selectSubnet(pkt);
     EXPECT_EQ(selected, subnet2);
 
     // CASE 3: We have three subnets defined and we received relayed traffic
     // that came out of subnet 2. We should select subnet2 then
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1);
-    CfgMgr::instance().addSubnet6(subnet2);
-    CfgMgr::instance().addSubnet6(subnet3);
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
+    CfgMgr::instance().commit();
 
     // Source of the packet should have no meaning. Selection is based
     // on linkaddr field in the relay
@@ -1331,10 +1342,11 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
 
     // CASE 4: We have three subnets defined and we received relayed traffic
     // that came out of undefined subnet. We should select nothing
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1);
-    CfgMgr::instance().addSubnet6(subnet2);
-    CfgMgr::instance().addSubnet6(subnet3);
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
+    CfgMgr::instance().commit();
     pkt->relay_info_.clear();
     relay.linkaddr_ = IOAddress("2001:db8:4::1234");
     pkt->relay_info_.push_back(relay);
@@ -1357,8 +1369,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayInterfaceId) {
 
     // CASE 1: We have only one subnet defined and it is for interface-id "relay1"
     // Packet came with interface-id "relay2". We should not select subnet1
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
+    CfgMgr::instance().commit();
 
     Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     Pkt6::RelayInfo relay;
@@ -1374,18 +1387,20 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayInterfaceId) {
 
     // CASE 2: We have only one subnet defined and it is for interface-id "relay2"
     // Packet came with interface-id "relay2". We should select it
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet2); // just a single subnet
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2); // just a single subnet
+    CfgMgr::instance().commit();
     selected = srv.selectSubnet(pkt);
     EXPECT_EQ(selected, subnet2);
 
     // CASE 3: We have only 3 subnets defined: one remote for interface-id "relay1",
     // one remote for interface-id "relay2" and third local
     // packet comes with interface-id "relay2". We should select subnet2
-    CfgMgr::instance().deleteSubnets6();
-    CfgMgr::instance().addSubnet6(subnet1);
-    CfgMgr::instance().addSubnet6(subnet2);
-    CfgMgr::instance().addSubnet6(subnet3);
+    CfgMgr::instance().clear();
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
+    CfgMgr::instance().commit();
 
     EXPECT_EQ(subnet2, srv.selectSubnet(pkt));
 }
@@ -1938,7 +1953,8 @@ TEST_F(Dhcpv6SrvTest, relayOverride) {
     ASSERT_NO_THROW(configure(config));
 
     // Let's get the subnet configuration objects
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
     ASSERT_EQ(2, subnets->size());
 
     // Let's get them for easy reference
@@ -2014,7 +2030,8 @@ TEST_F(Dhcpv6SrvTest, relayOverrideAndClientClass) {
     ASSERT_NO_THROW(configure(config));
 
     // Let's get the subnet configuration objects
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
     ASSERT_EQ(2, subnets->size());
 
     // Let's get them for easy reference

+ 5 - 2
src/bin/dhcp6/tests/dhcp6_test_utils.cc

@@ -36,8 +36,9 @@ Dhcpv6SrvTest::Dhcpv6SrvTest()
                               64));
     subnet_->addPool(pool_);
 
-    isc::dhcp::CfgMgr::instance().deleteSubnets6();
-    isc::dhcp::CfgMgr::instance().addSubnet6(subnet_);
+    isc::dhcp::CfgMgr::instance().clear();
+    isc::dhcp::CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet_);
+    isc::dhcp::CfgMgr::instance().commit();
 
     // configure PD pool
     pd_pool_ = isc::dhcp::Pool6Ptr
@@ -604,6 +605,8 @@ Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
     int rcode;
     ConstElementPtr comment = config::parseAnswer(rcode, status);
     ASSERT_EQ(0, rcode);
+
+    CfgMgr::instance().commit();
 }
 
 // Generate IA_NA option with specified parameters

+ 1 - 1
src/bin/dhcp6/tests/dhcp6_test_utils.h

@@ -348,7 +348,7 @@ public:
     ///
     /// Removes existing configuration.
     ~Dhcpv6SrvTest() {
-        isc::dhcp::CfgMgr::instance().deleteSubnets6();
+        isc::dhcp::CfgMgr::instance().clear();
     };
 
     /// @brief Runs DHCPv6 configuration from the JSON string.

+ 3 - 2
src/bin/dhcp6/tests/fqdn_unittest.cc

@@ -974,13 +974,14 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestReuseExpiredLease) {
     // We are going to configure a subnet with a pool that consists of
     // exactly one address. This address will be handed out to the
     // client, will get expired and then be reused.
-    CfgMgr::instance().deleteSubnets6();
+    CfgMgr::instance().clear();
     subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1:1::"), 56, 1, 2,
                                      3, 4));
     subnet_->setIface("eth0");
     pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, addr, addr));
     subnet_->addPool(pool_);
-    CfgMgr::instance().addSubnet6(subnet_);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet_);
+    CfgMgr::instance().commit();
 
     // Allocate a lease.
     testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",

+ 8 - 2
src/bin/dhcp6/tests/hooks_unittest.cc

@@ -922,6 +922,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet6_select) {
     comment_ = parseAnswer(rcode_, status);
     ASSERT_EQ(0, rcode_);
 
+    CfgMgr::instance().commit();
+
     // Prepare solicit packet. Server should select first subnet for it
     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     sol->setRemoteAddr(IOAddress("fe80::abcd"));
@@ -942,7 +944,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet6_select) {
     // Check that pkt6 argument passing was successful and returned proper value
     EXPECT_TRUE(callback_pkt6_.get() == sol.get());
 
-    const Subnet6Collection* exp_subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* exp_subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
 
     // The server is supposed to pick the first subnet, because of matching
     // interface. Check that the value is reported properly.
@@ -990,6 +993,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet_select_change) {
     comment_ = parseAnswer(rcode_, status);
     ASSERT_EQ(0, rcode_);
 
+    CfgMgr::instance().commit();
+
     // Prepare solicit packet. Server should select first subnet for it
     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     sol->setRemoteAddr(IOAddress("fe80::abcd"));
@@ -1016,7 +1021,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet_select_change) {
     ASSERT_TRUE(addr_opt);
 
     // Get all subnets and use second subnet for verification
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
     ASSERT_EQ(2, subnets->size());
 
     // Advertised address must belong to the second pool (in subnet's range,

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

@@ -106,7 +106,8 @@ TEST_F(JSONFileBackendTest, jsonFile) {
     EXPECT_NO_THROW(srv->init(TEST_FILE));
 
     // Now check if the configuration has been applied correctly.
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(3, subnets->size()); // We expect 3 subnets.
 
@@ -176,7 +177,8 @@ TEST_F(JSONFileBackendTest, comments) {
     EXPECT_NO_THROW(srv->init(TEST_FILE));
 
     // Now check if the configuration has been applied correctly.
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets =
+        CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
     ASSERT_TRUE(subnets);
     ASSERT_EQ(1, subnets->size());
 

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

@@ -223,8 +223,8 @@ TEST_F(RebindTest, directClient) {
     // subnets.
     ASSERT_EQ(1, client.getLeaseNum());
     Lease6 lease_client2 = client.getLease(0);
-    ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client2.addr_,
-                                              ClientClasses()));
+    ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
+                selectSubnet(lease_client2.addr_, ClientClasses()));
     // The client's lease should have been extended. The client will
     // update the cltt to current time when the lease gets extended.
     ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
@@ -337,8 +337,8 @@ TEST_F(RebindTest, relayedClient) {
     // subnets.
     ASSERT_EQ(1, client.getLeaseNum());
     Lease6 lease_client2 = client.getLease(0);
-    ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client2.addr_,
-                                              ClientClasses()));
+    ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
+                selectSubnet(lease_client2.addr_, ClientClasses()));
     // The client's lease should have been extended. The client will
     // update the cltt to current time when the lease gets extended.
     ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
@@ -498,8 +498,8 @@ TEST_F(RebindTest, directClientPD) {
     // subnets.
     ASSERT_EQ(1, client.getLeaseNum());
     Lease6 lease_client2 = client.getLease(0);
-    ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client2.addr_,
-                                              ClientClasses()));
+    ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
+                selectSubnet(lease_client2.addr_, ClientClasses()));
     // The client's lease should have been extended. The client will
     // update the cltt to current time when the lease gets extended.
     ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
@@ -675,8 +675,8 @@ TEST_F(RebindTest, relayedUnicast) {
     // subnets.
     ASSERT_EQ(1, client.getLeaseNum());
     Lease6 lease_client2 = client.getLease(0);
-    ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client2.addr_,
-                                              ClientClasses()));
+    ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
+                selectSubnet(lease_client2.addr_, ClientClasses()));
     // The client's lease should have been extended. The client will
     // update the cltt to current time when the lease gets extended.
     ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);

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

@@ -76,7 +76,8 @@ TEST_F(SARRTest, directClientPrefixHint) {
     client.usePD();
     configure(CONFIGS[0], *client.getServer());
     // Make sure we ended-up having expected number of subnets configured.
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
+        getCfgSubnets6()->getAll();
     ASSERT_EQ(1, subnets->size());
     // Append IAPREFIX option to the client's message.
     ASSERT_NO_THROW(client.useHint(100, 200, 64, "2001:db8:3:33::33"));

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

@@ -49,7 +49,7 @@ CfgSubnets6::selectSubnet(const SubnetSelector& selector) const {
         }
 
         // If interface name didn't match, try the client's address.
-        if (!subnet && selector.remote_address_.isSpecified()) {
+        if (!subnet && selector.remote_address_ != IOAddress("::")) {
             subnet = selectSubnet(selector.remote_address_,
                                   selector.client_classes_);
         }

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

@@ -62,114 +62,6 @@ CfgMgr::addOptionSpace6(const OptionSpacePtr& space) {
     spaces6_.insert(make_pair(space->getName(), space));
 }
 
-Subnet6Ptr
-CfgMgr::getSubnet6(const std::string& iface,
-                   const isc::dhcp::ClientClasses& classes) {
-
-    if (!iface.length()) {
-        return (Subnet6Ptr());
-    }
-
-    // If there is more than one, we need to choose the proper one
-    for (Subnet6Collection::iterator subnet = subnets6_.begin();
-         subnet != subnets6_.end(); ++subnet) {
-
-        // If client is rejected because of not meeting client class criteria...
-        if (!(*subnet)->clientSupported(classes)) {
-            continue;
-        }
-
-        if (iface == (*subnet)->getIface()) {
-            LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
-                      DHCPSRV_CFGMGR_SUBNET6_IFACE)
-                .arg((*subnet)->toText()).arg(iface);
-            return (*subnet);
-        }
-    }
-    return (Subnet6Ptr());
-}
-
-Subnet6Ptr
-CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint,
-                   const isc::dhcp::ClientClasses& classes,
-                   const bool relay) {
-
-    // If there is more than one, we need to choose the proper one
-    for (Subnet6Collection::iterator subnet = subnets6_.begin();
-         subnet != subnets6_.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_SUBNET6_RELAY)
-                .arg((*subnet)->toText()).arg(hint.toText());
-            return (*subnet);
-        }
-
-        if ((*subnet)->inRange(hint)) {
-            LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_SUBNET6)
-                      .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_SUBNET6)
-              .arg(hint.toText());
-    return (Subnet6Ptr());
-}
-
-Subnet6Ptr CfgMgr::getSubnet6(OptionPtr iface_id_option,
-                              const isc::dhcp::ClientClasses& classes) {
-    if (!iface_id_option) {
-        return (Subnet6Ptr());
-    }
-
-    // Let's iterate over all subnets and for those that have interface-id
-    // defined, check if the interface-id is equal to what we are looking for
-    for (Subnet6Collection::iterator subnet = subnets6_.begin();
-         subnet != subnets6_.end(); ++subnet) {
-
-        // If client is rejected because of not meeting client class criteria...
-        if (!(*subnet)->clientSupported(classes)) {
-            continue;
-        }
-
-        if ( (*subnet)->getInterfaceId() &&
-             ((*subnet)->getInterfaceId()->equals(iface_id_option))) {
-            LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
-                      DHCPSRV_CFGMGR_SUBNET6_IFACE_ID)
-                .arg((*subnet)->toText());
-            return (*subnet);
-        }
-    }
-    return (Subnet6Ptr());
-}
-
-void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
-    /// @todo: Check that this new subnet does not cross boundaries of any
-    /// other already defined subnet.
-    /// @todo: Check that there is no subnet with the same interface-id
-    if (isDuplicate(*subnet)) {
-        isc_throw(isc::dhcp::DuplicateSubnetID, "ID of the new IPv6 subnet '"
-                  << subnet->getID() << "' is already in use");
-    }
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_SUBNET6)
-              .arg(subnet->toText());
-    subnets6_.push_back(subnet);
-}
-
-void CfgMgr::deleteSubnets6() {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_DELETE_SUBNET6);
-    subnets6_.clear();
-}
-
 
 std::string CfgMgr::getDataDir() {
     return (datadir_);

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

@@ -126,97 +126,6 @@ public:
         return (spaces6_);
     }
 
-    /// @brief get IPv6 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.
-    ///
-    /// @note The client classification is checked before any relay
-    /// information checks are conducted.
-    ///
-    /// If relay is true then relay info overrides (i.e. value the sysadmin
-    /// can configure in Dhcp6/subnet6[X]/relay/ip-address) can be used.
-    /// That is applicable only for relays. Those overrides must not be used
-    /// for client address or for client hints. They are for link-addr field
-    /// in the RELAY_FORW message 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 (or NULL if no suitable match was fount)
-    Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint,
-                          const isc::dhcp::ClientClasses& classes,
-                          const bool relay = false);
-
-    /// @brief get IPv6 subnet by interface name
-    ///
-    /// Finds a matching local subnet, based on interface name. This
-    /// is used for selecting subnets that were explicitly marked by the
-    /// user as reachable over specified network interface.
-    ///
-    /// If there are any classes specified in a subnet, that subnet
-    /// will be selected only if the client belongs to appropriate class.
-    ///
-    /// @param iface_name interface name
-    /// @param classes classes the client belongs to
-    ///
-    /// @return a subnet object (or NULL if no suitable match was fount)
-    Subnet6Ptr getSubnet6(const std::string& iface_name,
-                          const isc::dhcp::ClientClasses& classes);
-
-    /// @brief get IPv6 subnet by interface-id
-    ///
-    /// Another possibility to find a subnet is based on interface-id.
-    ///
-    /// If there are any classes specified in a subnet, that subnet
-    /// will be selected only if the client belongs to appropriate class.
-    ///
-    /// @param interface_id content of interface-id option returned by a relay
-    /// @param classes classes the client belongs to
-    ///
-    /// @return a subnet object
-    Subnet6Ptr getSubnet6(OptionPtr interface_id,
-                          const isc::dhcp::ClientClasses& classes);
-
-    /// @brief adds an IPv6 subnet
-    ///
-    /// @param subnet new subnet to be added.
-    void addSubnet6(const Subnet6Ptr& subnet);
-
-    /// @todo: Add subnet6 removal routines. Currently it is not possible
-    /// to remove subnets. The only case where subnet6 removal would be
-    /// needed is a dynamic server reconfiguration - a use case that is not
-    /// planned to be supported any time soon.
-
-    /// @brief removes all IPv6 subnets
-    ///
-    /// This method removes all existing IPv6 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
-    /// 2000::/64 and 2000::/48 the same subnet or is it something
-    /// completely new?
-    void deleteSubnets6();
-
-    /// @brief returns const reference to all subnets6
-    ///
-    /// This is used in a hook (subnet6_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 Subnet6 collection
-    const Subnet6Collection* getSubnets6() {
-        return (&subnets6_);
-    }
-
     /// @brief returns path do the data directory
     ///
     /// This method returns a path to writeable directory that DHCP servers

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

@@ -51,7 +51,7 @@ SrvConfig::getConfigSummary(const uint32_t selection) const {
     }
 
     if ((selection & CFGSEL_SUBNET6) == CFGSEL_SUBNET6) {
-        subnets_num = CfgMgr::instance().getSubnets6()->size();
+        subnets_num = getCfgSubnets6()->getAll()->size();
         if (subnets_num > 0) {
             s << "added IPv6 subnets: " << subnets_num;
         } else {

+ 4 - 5
src/lib/dhcpsrv/subnet_selector.h

@@ -18,7 +18,6 @@
 #include <asiolink/io_address.h>
 #include <dhcp/classify.h>
 #include <dhcp/option.h>
-#include <util/optional_value.h>
 #include <string>
 
 namespace isc {
@@ -47,9 +46,9 @@ struct SubnetSelector {
     //@}
 
     /// @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.
     ClientClasses client_classes_;
     /// @brief Name of the interface on which the message was received.
@@ -63,8 +62,8 @@ struct SubnetSelector {
           giaddr_(asiolink::IOAddress("0.0.0.0")),
           interface_id_(),
           first_relay_linkaddr_(asiolink::IOAddress("::")),
-          local_address_(asiolink::IOAddress("0.0.0.0"), false),
-          remote_address_(asiolink::IOAddress("0.0.0.0"), false),
+          local_address_(asiolink::IOAddress("0.0.0.0")),
+          remote_address_(asiolink::IOAddress("0.0.0.0")),
           client_classes_(), iface_name_(std::string()) {
     }
 };

+ 9 - 6
src/lib/dhcpsrv/tests/alloc_engine_unittest.cc

@@ -91,6 +91,8 @@ public:
     /// in many tests, initializes cfg_mgr configuration and creates
     /// lease database.
     AllocEngine6Test() {
+        CfgMgr::instance().clear();
+
         duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
         iaid_ = 42;
 
@@ -115,7 +117,6 @@ public:
     void initSubnet(const IOAddress& subnet, const IOAddress& pool_start,
                     const IOAddress& pool_end) {
         CfgMgr& cfg_mgr = CfgMgr::instance();
-        cfg_mgr.deleteSubnets6();
 
         subnet_ = Subnet6Ptr(new Subnet6(subnet, 56, 1, 2, 3, 4));
         pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, pool_start, pool_end));
@@ -125,7 +126,8 @@ public:
         pd_pool_ = Pool6Ptr(new Pool6(Lease::TYPE_PD, subnet, 56, 64));
         subnet_->addPool(pd_pool_);
 
-        cfg_mgr.addSubnet6(subnet_);
+        cfg_mgr.getStagingCfg()->getCfgSubnets6()->add(subnet_);
+        cfg_mgr.commit();
 
     }
 
@@ -855,13 +857,13 @@ TEST_F(AllocEngine6Test, outOfAddresses6) {
 
     IOAddress addr("2001:db8:1::ad");
     CfgMgr& cfg_mgr = CfgMgr::instance();
-    cfg_mgr.deleteSubnets6(); // Get rid of the default test configuration
+    cfg_mgr.clear(); // Get rid of the default test configuration
 
     // Create configuration similar to other tests, but with a single address pool
     subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
     pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, addr, addr)); // just a single address
     subnet_->addPool(pool_);
-    cfg_mgr.addSubnet6(subnet_);
+    cfg_mgr.getStagingCfg()->getCfgSubnets6()->add(subnet_);
 
     // Just a different duid
     DuidPtr other_duid = DuidPtr(new DUID(vector<uint8_t>(12, 0xff)));
@@ -939,13 +941,14 @@ TEST_F(AllocEngine6Test, requestReuseExpiredLease6) {
 
     IOAddress addr("2001:db8:1::ad");
     CfgMgr& cfg_mgr = CfgMgr::instance();
-    cfg_mgr.deleteSubnets6(); // Get rid of the default test configuration
+    cfg_mgr.clear(); // Get rid of the default test configuration
 
     // Create configuration similar to other tests, but with a single address pool
     subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
     pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, addr, addr)); // just a single address
     subnet_->addPool(pool_);
-    cfg_mgr.addSubnet6(subnet_);
+    cfg_mgr.getStagingCfg()->getCfgSubnets6()->add(subnet_);
+    cfg_mgr.commit();
 
     // Let's create an expired lease
     DuidPtr other_duid = DuidPtr(new DUID(vector<uint8_t>(12, 0xff)));

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

@@ -283,7 +283,6 @@ public:
 
     void clear() {
         CfgMgr::instance().setVerbose(false);
-        CfgMgr::instance().deleteSubnets6();
         CfgMgr::instance().clear();
     }
 
@@ -304,307 +303,6 @@ TEST_F(CfgMgrTest, configuration) {
     EXPECT_TRUE(configuration->getLoggingInfo().empty());
 }
 
-// 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.
-TEST_F(CfgMgrTest, subnet6RelayOverride) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    // Let's configure 3 subnets
-    Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
-
-    cfg_mgr.addSubnet6(subnet1);
-    cfg_mgr.addSubnet6(subnet2);
-    cfg_mgr.addSubnet6(subnet3);
-
-    // Check that without relay-info specified, subnets are not selected
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::1"), classify_, true));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::2"), classify_, true));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::3"), classify_, true));
-
-    // Now specify relay info
-    subnet1->setRelayInfo(IOAddress("2001:db8:ff::1"));
-    subnet2->setRelayInfo(IOAddress("2001:db8:ff::2"));
-    subnet3->setRelayInfo(IOAddress("2001:db8:ff::3"));
-
-    // And try again. This time relay-info is there and should match.
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::1"), classify_, true));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::2"), classify_, true));
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::3"), classify_, true));
-
-    // Finally, check that the relay works only if hint provided is relay address
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::1"), classify_, false));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::2"), classify_, false));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::3"), classify_, false));
-}
-
-
-// This test verifies if the configuration manager is able to hold and return
-// valid leases
-TEST_F(CfgMgrTest, classifySubnet6) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    // Let's configure 3 subnets
-    Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
-
-    cfg_mgr.addSubnet6(subnet1);
-    cfg_mgr.addSubnet6(subnet2);
-    cfg_mgr.addSubnet6(subnet3);
-
-    // Let's sanity check that we can use that configuration.
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::567"), 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.getSubnet6(IOAddress("2000::123"), classify_));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::567"), 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.getSubnet6(IOAddress("2000::123"), classify_));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
-
-    // Now let's check that client with wrong class is not supported
-    classify_.clear();
-    classify_.insert("some_other_class");
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
-
-    // Finally, let's check that client without any classes is not supported
-    classify_.clear();
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
-}
-
-// This test verifies if the configuration manager is able to hold, select
-// and return valid subnets, based on interface names along with client
-// classification.
-TEST_F(CfgMgrTest, classifySubnet6Interface) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    // Let's have an odd configuration: 3 shared subnets available on the
-    // same direct link.
-    Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
-    subnet1->setIface("foo");
-    subnet2->setIface("foo");
-    subnet3->setIface("foo");
-    cfg_mgr.addSubnet6(subnet1);
-    cfg_mgr.addSubnet6(subnet2);
-    cfg_mgr.addSubnet6(subnet3);
-
-
-    // Regular client should get the first subnet, because it meets all
-    // criteria (matching interface name, no class restrictions.
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6("foo", classify_));
-
-    // Now let's add class requirements for subnet1
-    subnet1->allowClientClass("alpha");
-
-    // Client should now get the subnet2, because he no longer meets
-    // requirements for subnet1 (belongs to wrong class)
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6("foo", classify_));
-
-    // Now let's add (not matching) classes to the other two subnets
-    subnet2->allowClientClass("beta");
-    subnet3->allowClientClass("gamma");
-
-    // No subnets are suitable, so nothing will be selected
-    EXPECT_FALSE(cfg_mgr.getSubnet6("foo", classify_));
-
-    // Ok, let's add the client to gamme class, so he'll get a subnet
-    classify_.insert("gamma");
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6("foo", classify_));
-}
-
-// This test verifies if the configuration manager is able to hold, select
-// and return valid subnets, based on interface-id option inserted by relay,
-// along with client classification.
-TEST_F(CfgMgrTest, classifySubnet6InterfaceId) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    // Let's have an odd configuration: 3 shared subnets available via the
-    // same remote relay with the same interface-id.
-    Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
-    OptionPtr ifaceid = generateInterfaceId("relay1.eth0");
-    subnet1->setInterfaceId(ifaceid);
-    subnet2->setInterfaceId(ifaceid);
-    subnet3->setInterfaceId(ifaceid);
-    cfg_mgr.addSubnet6(subnet1);
-    cfg_mgr.addSubnet6(subnet2);
-    cfg_mgr.addSubnet6(subnet3);
-
-    // Regular client should get the first subnet, because it meets all
-    // criteria (matching interface name, no class restrictions.
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(ifaceid, classify_));
-
-    // Now let's add class requirements for subnet1
-    subnet1->allowClientClass("alpha");
-
-    // Client should now get the subnet2, because he no longer meets
-    // requirements for subnet1 (belongs to wrong class)
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(ifaceid, classify_));
-
-    // Now let's add (not matching) classes to the other two subnets
-    subnet2->allowClientClass("beta");
-    subnet3->allowClientClass("gamma");
-
-    // No subnets are suitable, so nothing will be selected
-    EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid, classify_));
-
-    // Ok, let's add the client to gamme class, so he'll get a subnet
-    classify_.insert("gamma");
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(ifaceid, classify_));
-}
-
-// This test verifies if the configuration manager is able to hold and return
-// valid leases
-TEST_F(CfgMgrTest, subnet6) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
-
-    // There shouldn't be any subnet configured at this stage
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::1"), classify_));
-
-    cfg_mgr.addSubnet6(subnet1);
-
-    // Now we have only one subnet, any request will be served from it
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::1"), classify_));
-
-    // We used to allow getting a sole subnet if there was only one subnet
-    // configured. That is no longer true. The code should not return
-    // a subnet.
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef"), classify_));
-
-    cfg_mgr.addSubnet6(subnet2);
-    cfg_mgr.addSubnet6(subnet3);
-
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::123"), classify_));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef"),
-                  classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("5000::1"), classify_));
-
-    // Check that deletion of the subnets works.
-    cfg_mgr.deleteSubnets6();
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::123"), classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::123"), classify_));
-}
-
-// This test verifies if the configuration manager is able to hold, select
-// and return valid subnets, based on interface names.
-TEST_F(CfgMgrTest, subnet6Interface) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
-    subnet1->setIface("foo");
-    subnet2->setIface("bar");
-    subnet3->setIface("foobar");
-
-    // There shouldn't be any subnet configured at this stage
-    EXPECT_FALSE(cfg_mgr.getSubnet6("foo", classify_));
-
-    cfg_mgr.addSubnet6(subnet1);
-
-    // Now we have only one subnet, any request will be served from it
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6("foo", classify_));
-
-    // Check that the interface name is checked even when there is
-    // only one subnet defined.
-    EXPECT_FALSE(cfg_mgr.getSubnet6("bar", classify_));
-
-    // We used to allow getting a sole subnet if there was only one subnet
-    // configured. That is no longer true. The code should not return
-    // a subnet.
-    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef"), classify_));
-
-    cfg_mgr.addSubnet6(subnet2);
-    cfg_mgr.addSubnet6(subnet3);
-
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6("foobar", classify_));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6("bar", classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6("xyzzy", classify_)); // no such interface
-
-    // Check that deletion of the subnets works.
-    cfg_mgr.deleteSubnets6();
-    EXPECT_FALSE(cfg_mgr.getSubnet6("foo", classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6("bar", classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6("foobar", classify_));
-}
-
-// This test verifies if the configuration manager is able to hold, select
-// and return valid leases, based on interface-id option values
-TEST_F(CfgMgrTest, subnet6InterfaceId) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
-    Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
-
-    // interface-id options used in subnets 1,2, and 3
-    OptionPtr ifaceid1 = generateInterfaceId("relay1.eth0");
-    OptionPtr ifaceid2 = generateInterfaceId("VL32");
-    // That's a strange interface-id, but this is a real life example
-    OptionPtr ifaceid3 = generateInterfaceId("ISAM144|299|ipv6|nt:vp:1:110");
-
-    // bogus interface-id
-    OptionPtr ifaceid_bogus = generateInterfaceId("non-existent");
-
-    subnet1->setInterfaceId(ifaceid1);
-    subnet2->setInterfaceId(ifaceid2);
-    subnet3->setInterfaceId(ifaceid3);
-
-    // There shouldn't be any subnet configured at this stage
-    EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid1, classify_));
-
-    cfg_mgr.addSubnet6(subnet1);
-
-    // If we have only a single subnet and the request came from a local
-    // address, let's use that subnet
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(ifaceid1, classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid2, classify_));
-
-    cfg_mgr.addSubnet6(subnet2);
-    cfg_mgr.addSubnet6(subnet3);
-
-    EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(ifaceid3, classify_));
-    EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(ifaceid2, classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid_bogus, classify_));
-
-    // Check that deletion of the subnets works.
-    cfg_mgr.deleteSubnets6();
-    EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid1, classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid2, classify_));
-    EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid3, classify_));
-}
-
-
 // This test verifies that new DHCPv4 option spaces can be added to
 // the configuration manager and that duplicated option space is
 // rejected.
@@ -731,26 +429,6 @@ TEST_F(CfgMgrTest, d2ClientConfig) {
     EXPECT_NE(*original_config, *updated_config);
 }
 
-// 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.
-TEST_F(CfgMgrTest, subnet6Duplication) {
-    CfgMgr& cfg_mgr = CfgMgr::instance();
-
-    Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 64, 1, 2, 3,
-                                   4, 123));
-    Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 64, 1, 2, 3,
-                                   4, 124));
-    Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 64, 1, 2, 3,
-                                   4, 123));
-
-    ASSERT_NO_THROW(cfg_mgr.addSubnet6(subnet1));
-    EXPECT_NO_THROW(cfg_mgr.addSubnet6(subnet2));
-    // Subnet 3 has the same ID as subnet 1. It shouldn't be able to add it.
-    EXPECT_THROW(cfg_mgr.addSubnet6(subnet3), isc::dhcp::DuplicateSubnetID);
-}
-
-
 // This test verifies that the configuration staging, commit and rollback works
 // as expected.
 TEST_F(CfgMgrTest, staging) {

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

@@ -447,7 +447,6 @@ public:
     void reset_context(){
         // Note set context universe to V6 as it has to be something.
         CfgMgr::instance().clear();
-        CfgMgr::instance().deleteSubnets6();
         parser_context_.reset(new ParserContext(Option::V6));
 
         // Ensure no hooks libraries are loaded.

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

@@ -41,8 +41,6 @@ public:
     /// is @c TEST_SUBNETS_NUM for IPv4 and IPv6 each.
     SrvConfigTest()
         : iface_mgr_test_config_(true) {
-        // Remove any subnets dangling from previous unit tests.
-        clearSubnets();
 
         // Disable DDNS.
         enableDDNS(false);
@@ -74,10 +72,7 @@ public:
     }
 
     /// @brief Destructor.
-    ///
-    /// Removes any dangling configuration.
     virtual ~SrvConfigTest() {
-        clearSubnets();
     }
 
     /// @brief Convenience function which adds IPv4 subnet to the configuration.
@@ -108,12 +103,6 @@ public:
     /// @c conf_ object.
     void addSubnet6(const unsigned int index);
 
-    /// @brief Removes all subnets from the configuration.
-    ///
-    /// @todo Modify this function once the subnet configuration is migrated
-    /// from @c CfgMgr to @c SrvConfig.
-    void clearSubnets();
-
     /// @brief Enable/disable DDNS.
     ///
     /// @param enable A boolean value indicating if the DDNS should be
@@ -146,12 +135,7 @@ SrvConfigTest::addSubnet6(const unsigned int index) {
         FAIL() << "Subnet index " << index << "out of range (0.."
                << TEST_SUBNETS_NUM << "): " << "unable to add IPv6 subnet";
     }
-    CfgMgr::instance().addSubnet6(test_subnets6_[index]);
-}
-
-void
-SrvConfigTest::clearSubnets() {
-    CfgMgr::instance().deleteSubnets6();
+    conf_.getCfgSubnets6()->add(test_subnets6_[index]);
 }
 
 void