Browse Source

[5019] Subnet4, Subne6 parsers migrated to SimpleParser

Tomek Mrugalski 8 years ago
parent
commit
26be56dec1

+ 61 - 81
src/bin/dhcp4/json_config_parser.cc

@@ -108,9 +108,8 @@ class Subnet4ConfigParser : public SubnetConfigParser {
 public:
 public:
     /// @brief Constructor
     /// @brief Constructor
     ///
     ///
-    /// @param ignored first parameter
     /// stores global scope parameters, options, option definitions.
     /// stores global scope parameters, options, option definitions.
-    Subnet4ConfigParser(const std::string&)
+    Subnet4ConfigParser()
         :SubnetConfigParser("", globalContext(), IOAddress("0.0.0.0")) {
         :SubnetConfigParser("", globalContext(), IOAddress("0.0.0.0")) {
     }
     }
 
 
@@ -118,7 +117,8 @@ public:
     /// Configuration Manager.
     /// Configuration Manager.
     ///
     ///
     /// @param subnet A new subnet being configured.
     /// @param subnet A new subnet being configured.
-    void build(ConstElementPtr subnet) {
+    /// @return a pointer to created Subnet4 object
+    Subnet4Ptr parse(ConstElementPtr subnet) {
         /// Parse Pools first.
         /// Parse Pools first.
         ConstElementPtr pools = subnet->get("pools");
         ConstElementPtr pools = subnet->get("pools");
         if (pools) {
         if (pools) {
@@ -126,30 +126,18 @@ public:
             parser.parse(pools_, pools);
             parser.parse(pools_, pools);
         }
         }
 
 
-        SubnetConfigParser::build(subnet);
+        SubnetPtr generic = SubnetConfigParser::build(subnet);
 
 
-        if (subnet_) {
-            Subnet4Ptr sub4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_);
-            if (!sub4ptr) {
-                // If we hit this, it is a programming error.
-                isc_throw(Unexpected,
-                          "Invalid cast in Subnet4ConfigParser::commit");
-            }
-
-            // Set relay information if it was parsed
-            if (relay_info_) {
-                sub4ptr->setRelayInfo(*relay_info_);
-            }
+        Subnet4Ptr sub4ptr = boost::dynamic_pointer_cast<Subnet4>(generic);
+        if (!sub4ptr) {
+            // If we hit this, it is a programming error.
+            isc_throw(Unexpected,
+                      "Invalid Subnet4 cast in Subnet4ConfigParser::parse");
+        }
 
 
-            // Adding a subnet to the Configuration Manager may fail if the
-            // subnet id is invalid (duplicate). Thus, we catch exceptions
-            // here to append a position in the configuration string.
-            try {
-                CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(sub4ptr);
-            } catch (const std::exception& ex) {
-                isc_throw(DhcpConfigError, ex.what() << " ("
-                          << subnet->getPosition() << ")");
-            }
+        // Set relay information if it was parsed
+        if (relay_info_) {
+            sub4ptr->setRelayInfo(*relay_info_);
         }
         }
 
 
         // Parse Host Reservations for this subnet if any.
         // Parse Host Reservations for this subnet if any.
@@ -158,13 +146,9 @@ public:
             HostReservationsListParser<HostReservationParser4> parser;
             HostReservationsListParser<HostReservationParser4> parser;
             parser.parse(subnet_->getID(), reservations);
             parser.parse(subnet_->getID(), reservations);
         }
         }
-    }
 
 
-    /// @brief Commits subnet configuration.
-    ///
-    /// This function is currently no-op because subnet should already
-    /// be added into the Config Manager in the build().
-    void commit() { }
+        return (sub4ptr);
+    }
 
 
 protected:
 protected:
 
 
@@ -358,40 +342,38 @@ protected:
 /// This is a wrapper parser that handles the whole list of Subnet4
 /// This is a wrapper parser that handles the whole list of Subnet4
 /// definitions. It iterates over all entries and creates Subnet4ConfigParser
 /// definitions. It iterates over all entries and creates Subnet4ConfigParser
 /// for each entry.
 /// for each entry.
-class Subnets4ListConfigParser : public DhcpConfigParser {
+class Subnets4ListConfigParser : public isc::data::SimpleParser {
 public:
 public:
 
 
-    /// @brief constructor
-    ///
-    /// @param dummy first argument, always ignored. All parsers accept a
-    /// string parameter "name" as their first argument.
-    Subnets4ListConfigParser(const std::string&) {
-    }
-
     /// @brief parses contents of the list
     /// @brief parses contents of the list
     ///
     ///
-    /// Iterates over all entries on the list and creates Subnet4ConfigParser
-    /// for each entry.
+    /// Iterates over all entries on the list, parses its content
+    /// (by instantiating Subnet6ConfigParser) and adds to specified
+    /// configuration.
     ///
     ///
     /// @param subnets_list pointer to a list of IPv4 subnets
     /// @param subnets_list pointer to a list of IPv4 subnets
-    void build(ConstElementPtr subnets_list) {
-        BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
-            ParserPtr parser(new Subnet4ConfigParser("subnet"));
-            parser->build(subnet);
+    /// @return number of subnets created
+    size_t parse(SrvConfigPtr cfg, ConstElementPtr subnets_list) {
+        size_t cnt = 0;
+        BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
+
+            Subnet4ConfigParser parser;
+            Subnet4Ptr subnet = parser.parse(subnet_json);
+            if (subnet) {
+
+                // Adding a subnet to the Configuration Manager may fail if the
+                // subnet id is invalid (duplicate). Thus, we catch exceptions
+                // here to append a position in the configuration string.
+                try {
+                    cfg->getCfgSubnets4()->add(subnet);
+                    cnt++;
+                } catch (const std::exception& ex) {
+                    isc_throw(DhcpConfigError, ex.what() << " ("
+                              << subnet_json->getPosition() << ")");
+                }
+            }
         }
         }
-    }
-
-    /// @brief commits subnets definitions.
-    ///
-    /// Does nothing.
-    void commit() {
-    }
-
-    /// @brief Returns Subnet4ListConfigParser object
-    /// @param param_name name of the parameter
-    /// @return Subnets4ListConfigParser object
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new Subnets4ListConfigParser(param_name));
+        return (cnt);
     }
     }
 };
 };
 
 
@@ -420,8 +402,7 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id,
         (config_id.compare("dhcp4o6-port") == 0) )  {
         (config_id.compare("dhcp4o6-port") == 0) )  {
         parser = new Uint32Parser(config_id,
         parser = new Uint32Parser(config_id,
                                   globalContext()->uint32_values_);
                                   globalContext()->uint32_values_);
-    } else if (config_id.compare("subnet4") == 0) {
-        parser = new Subnets4ListConfigParser(config_id);
+    // subnet4 has been migrated to SimpleParser already.
     // interface-config has been migrated to SimpleParser already.
     // interface-config has been migrated to SimpleParser already.
     // option-data and option-def have been converted to SimpleParser already.
     // option-data and option-def have been converted to SimpleParser already.
     } else if ((config_id.compare("next-server") == 0)) {
     } else if ((config_id.compare("next-server") == 0)) {
@@ -564,7 +545,6 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
     // then: option-data parser, subnet4 parser, lease-database parser.
     // then: option-data parser, subnet4 parser, lease-database parser.
     // Please do not change this order!
     // Please do not change this order!
     ParserCollection independent_parsers;
     ParserCollection independent_parsers;
-    ParserPtr subnet_parser;
 
 
     // Some of the parsers alter the state of the system in a way that can't
     // Some of the parsers alter the state of the system in a way that can't
     // easily be undone. (Or alter it in a way such that undoing the change has
     // easily be undone. (Or alter it in a way such that undoing the change has
@@ -601,6 +581,9 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
         // Set all default values if not specified by the user.
         // Set all default values if not specified by the user.
         SimpleParser4::setAllDefaults(mutable_cfg);
         SimpleParser4::setAllDefaults(mutable_cfg);
 
 
+        // And now derive (inherit) global parameters to subnets, if not specified.
+        SimpleParser4::deriveParameters(mutable_cfg);
+
         // We need definitions first
         // We need definitions first
         ConstElementPtr option_defs = mutable_cfg->get("option-def");
         ConstElementPtr option_defs = mutable_cfg->get("option-def");
         if (option_defs) {
         if (option_defs) {
@@ -660,7 +643,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
                 hooks_parser.verifyLibraries();
                 hooks_parser.verifyLibraries();
                 continue;
                 continue;
             }
             }
-            
+
             // Legacy DhcpConfigParser stuff below
             // Legacy DhcpConfigParser stuff below
             if (config_pair.first == "dhcp-ddns") {
             if (config_pair.first == "dhcp-ddns") {
                 // Apply defaults if not in short cut
                 // Apply defaults if not in short cut
@@ -696,30 +679,27 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
                 continue;
                 continue;
             }
             }
 
 
+            if (config_pair.first == "subnet4") {
+                SrvConfigPtr srv_cfg = CfgMgr::instance().getStagingCfg();
+                Subnets4ListConfigParser subnets_parser;
+                // parse() returns number of subnets parsed. We may log it one day.
+                subnets_parser.parse(srv_cfg, config_pair.second);
+                continue;
+            }
+
             ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first,
             ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first,
                                                            config_pair.second));
                                                            config_pair.second));
             LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PARSER_CREATED)
             LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PARSER_CREATED)
                       .arg(config_pair.first);
                       .arg(config_pair.first);
-            if (config_pair.first == "subnet4") {
-                subnet_parser = parser;
-            } else {
-                // Those parsers should be started before other
-                // parsers so we can call build straight away.
-                independent_parsers.push_back(parser);
-                parser->build(config_pair.second);
-                // The commit operation here may modify the global storage
-                // but we need it so as the subnet6 parser can access the
-                // parsed data.
-                parser->commit();
-            }
-        }
 
 
-        // The subnet parser is the next one to be run.
-        std::map<std::string, ConstElementPtr>::const_iterator subnet_config =
-            values_map.find("subnet4");
-        if (subnet_config != values_map.end()) {
-            config_pair.first = "subnet4";
-            subnet_parser->build(subnet_config->second);
+            // Those parsers should be started before other
+            // parsers so we can call build straight away.
+            independent_parsers.push_back(parser);
+            parser->build(config_pair.second);
+            // The commit operation here may modify the global storage
+            // but we need it so as the subnet6 parser can access the
+            // parsed data.
+            parser->commit();
         }
         }
 
 
         // Setup the command channel.
         // Setup the command channel.

+ 14 - 0
src/bin/dhcp4/simple_parser4.cc

@@ -98,6 +98,20 @@ size_t SimpleParser4::setAllDefaults(isc::data::ElementPtr global) {
             cnt += SimpleParser::setDefaults(single_option, OPTION4_DEFAULTS);
             cnt += SimpleParser::setDefaults(single_option, OPTION4_DEFAULTS);
         }
         }
     }
     }
+    return (cnt);
+}
+
+size_t SimpleParser4::deriveParameters(isc::data::ElementPtr global) {
+    size_t cnt = 0;
+
+    // Now derive global parameters into subnets.
+    ConstElementPtr subnets = global->get("subnet4");
+    if (subnets) {
+        BOOST_FOREACH(ElementPtr single_subnet, subnets->listValue()) {
+            cnt += SimpleParser::deriveParams(global, single_subnet,
+                                              INHERIT_GLOBAL_TO_SUBNET4);
+        }
+    }
 
 
     return (cnt);
     return (cnt);
 }
 }

+ 8 - 0
src/bin/dhcp4/simple_parser4.h

@@ -28,6 +28,14 @@ public:
     /// @return number of default values added
     /// @return number of default values added
     static size_t setAllDefaults(isc::data::ElementPtr global);
     static size_t setAllDefaults(isc::data::ElementPtr global);
 
 
+    /// @brief Derives (inherits) all parameters from global to more specific scopes.
+    ///
+    /// This method currently does the following:
+    /// - derives global parameters to subnets (lifetimes for now)
+    /// @param global scope to be modified if needed (subnet4 will be extracted)
+    /// @return number of default values derived
+    static size_t deriveParameters(isc::data::ElementPtr global);
+
     // see simple_parser4.cc for comments for those parameters
     // see simple_parser4.cc for comments for those parameters
     static const isc::data::SimpleDefaults OPTION4_DEF_DEFAULTS;
     static const isc::data::SimpleDefaults OPTION4_DEF_DEFAULTS;
     static const isc::data::SimpleDefaults OPTION4_DEFAULTS;
     static const isc::data::SimpleDefaults OPTION4_DEFAULTS;

+ 8 - 4
src/bin/dhcp4/tests/simple_parser4_unittest.cc

@@ -69,15 +69,18 @@ TEST_F(SimpleParser4Test, inheritGlobalToSubnet4) {
     ElementPtr global = parseJSON("{ \"renew-timer\": 1,"
     ElementPtr global = parseJSON("{ \"renew-timer\": 1,"
                                   "  \"rebind-timer\": 2,"
                                   "  \"rebind-timer\": 2,"
                                   "  \"preferred-lifetime\": 3,"
                                   "  \"preferred-lifetime\": 3,"
-                                  "  \"valid-lifetime\": 4"
+                                  "  \"valid-lifetime\": 4,"
+                                  "  \"subnet4\": [ { \"renew-timer\": 100 } ] "
                                   "}");
                                   "}");
-    ElementPtr subnet = parseJSON("{ \"renew-timer\": 100 }");
+    ConstElementPtr subnets = global->find("subnet4");
+    ASSERT_TRUE(subnets);
+    ConstElementPtr subnet = subnets->get(0);
+    ASSERT_TRUE(subnet);
 
 
     // we should inherit 3 parameters. Renew-timer should remain intact,
     // we should inherit 3 parameters. Renew-timer should remain intact,
     // as it was already defined in the subnet scope.
     // as it was already defined in the subnet scope.
     size_t num;
     size_t num;
-    EXPECT_NO_THROW(num = SimpleParser4::deriveParams(global, subnet,
-                          SimpleParser4::INHERIT_GLOBAL_TO_SUBNET4));
+    EXPECT_NO_THROW(num = SimpleParser4::deriveParameters(global));
     EXPECT_EQ(2, num);
     EXPECT_EQ(2, num);
 
 
     // Check the values. 2 of them are inherited, while the third one
     // Check the values. 2 of them are inherited, while the third one
@@ -87,6 +90,7 @@ TEST_F(SimpleParser4Test, inheritGlobalToSubnet4) {
     checkIntegerValue(subnet, "valid-lifetime", 4);
     checkIntegerValue(subnet, "valid-lifetime", 4);
 }
 }
 
 
+
 };
 };
 };
 };
 };
 };

+ 70 - 96
src/bin/dhcp6/json_config_parser.cc

@@ -301,9 +301,8 @@ public:
 
 
     /// @brief Constructor
     /// @brief Constructor
     ///
     ///
-    /// @param ignored first parameter
     /// stores global scope parameters, options, option definitions.
     /// stores global scope parameters, options, option definitions.
-    Subnet6ConfigParser(const std::string&)
+    Subnet6ConfigParser()
         :SubnetConfigParser("", globalContext(), IOAddress("::")) {
         :SubnetConfigParser("", globalContext(), IOAddress("::")) {
     }
     }
 
 
@@ -311,7 +310,8 @@ public:
     /// Configuration Manager.
     /// Configuration Manager.
     ///
     ///
     /// @param subnet A new subnet being configured.
     /// @param subnet A new subnet being configured.
-    void build(ConstElementPtr subnet) {
+    /// @return a pointer to created Subnet6 object
+    Subnet6Ptr parse(ConstElementPtr subnet) {
         /// Parse all pools first.
         /// Parse all pools first.
         ConstElementPtr pools = subnet->get("pools");
         ConstElementPtr pools = subnet->get("pools");
         if (pools) {
         if (pools) {
@@ -324,45 +324,36 @@ public:
             parser.parse(pools_, pd_pools);
             parser.parse(pools_, pd_pools);
         }
         }
 
 
-        SubnetConfigParser::build(subnet);
+        SubnetPtr generic = SubnetConfigParser::build(subnet);
 
 
-        if (subnet_) {
-            Subnet6Ptr sub6ptr = boost::dynamic_pointer_cast<Subnet6>(subnet_);
-            if (!sub6ptr) {
-                // If we hit this, it is a programming error.
-                isc_throw(Unexpected,
-                          "Invalid cast in Subnet6ConfigParser::commit");
-            }
+        if (!generic) {
+            isc_throw(DhcpConfigError,
+                      "Failed to create an IPv6 subnet (" <<
+                      subnet->getPosition() << ")");
+        }
 
 
-            // Set relay information if it was provided
-            if (relay_info_) {
-                sub6ptr->setRelayInfo(*relay_info_);
-            }
+        Subnet6Ptr sub6ptr = boost::dynamic_pointer_cast<Subnet6>(subnet_);
+        if (!sub6ptr) {
+            // If we hit this, it is a programming error.
+            isc_throw(Unexpected,
+                      "Invalid Subnet6 cast in Subnet6ConfigParser::parse");
+        }
 
 
-            // Adding a subnet to the Configuration Manager may fail if the
-            // subnet id is invalid (duplicate). Thus, we catch exceptions
-            // here to append a position in the configuration string.
-            try {
-                CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(sub6ptr);
-            } catch (const std::exception& ex) {
-                isc_throw(DhcpConfigError, ex.what() << " ("
-                          << subnet->getPosition() << ")");
-            }
+        // Set relay information if it was provided
+        if (relay_info_) {
+            sub6ptr->setRelayInfo(*relay_info_);
+        }
 
 
-            // Parse Host Reservations for this subnet if any.
-            ConstElementPtr reservations = subnet->get("reservations");
-            if (reservations) {
-                HostReservationsListParser<HostReservationParser6> parser;
-                parser.parse(subnet_->getID(), reservations);
-            }
+
+        // Parse Host Reservations for this subnet if any.
+        ConstElementPtr reservations = subnet->get("reservations");
+        if (reservations) {
+            HostReservationsListParser<HostReservationParser6> parser;
+            parser.parse(subnet_->getID(), reservations);
         }
         }
-    }
 
 
-    /// @brief Commits subnet configuration.
-    ///
-    /// This function is currently no-op because subnet should already
-    /// be added into the Config Manager in the build().
-    void commit() { }
+        return (sub6ptr);
+    }
 
 
 protected:
 protected:
 
 
@@ -509,51 +500,38 @@ protected:
 /// This is a wrapper parser that handles the whole list of Subnet6
 /// This is a wrapper parser that handles the whole list of Subnet6
 /// definitions. It iterates over all entries and creates Subnet6ConfigParser
 /// definitions. It iterates over all entries and creates Subnet6ConfigParser
 /// for each entry.
 /// for each entry.
-class Subnets6ListConfigParser : public DhcpConfigParser {
+class Subnets6ListConfigParser : public isc::data::SimpleParser {
 public:
 public:
 
 
-    /// @brief constructor
-    ///
-    /// @param dummy first argument, always ignored. All parsers accept a
-    /// string parameter "name" as their first argument.
-    Subnets6ListConfigParser(const std::string&) {
-    }
-
     /// @brief parses contents of the list
     /// @brief parses contents of the list
     ///
     ///
-    /// Iterates over all entries on the list and creates a Subnet6ConfigParser
-    /// for each entry.
+    /// Iterates over all entries on the list, parses its content
+    /// (by instantiating Subnet6ConfigParser) and adds to specified
+    /// configuration.
     ///
     ///
+    /// @param cfg configuration (parsed subnets will be stored here)
     /// @param subnets_list pointer to a list of IPv6 subnets
     /// @param subnets_list pointer to a list of IPv6 subnets
-    void build(ConstElementPtr subnets_list) {
-        BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
-            ParserPtr parser(new Subnet6ConfigParser("subnet"));
-            parser->build(subnet);
-            subnets_.push_back(parser);
-        }
+    /// @throw DhcpConfigError if CfgMgr rejects the subnet (e.g. subnet-id is a duplicate)
+    size_t parse(SrvConfigPtr cfg, ConstElementPtr subnets_list) {
+        size_t cnt = 0;
+        BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
 
 
-    }
+            Subnet6ConfigParser parser;
+            Subnet6Ptr subnet = parser.parse(subnet_json);
 
 
-    /// @brief commits subnets definitions.
-    ///
-    /// Iterates over all Subnet6 parsers. Each parser contains definitions of
-    /// a single subnet and its parameters and commits each subnet separately.
-    void commit() {
-        BOOST_FOREACH(ParserPtr subnet, subnets_) {
-            subnet->commit();
+            // Adding a subnet to the Configuration Manager may fail if the
+            // subnet id is invalid (duplicate). Thus, we catch exceptions
+            // here to append a position in the configuration string.
+            try {
+                cfg->getCfgSubnets6()->add(subnet);
+                cnt++;
+            } catch (const std::exception& ex) {
+                isc_throw(DhcpConfigError, ex.what() << " ("
+                          << subnet_json->getPosition() << ")");
+            }
         }
         }
-
-    }
-
-    /// @brief Returns Subnet6ListConfigParser object
-    /// @param param_name name of the parameter
-    /// @return Subnets6ListConfigParser object
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new Subnets6ListConfigParser(param_name));
+        return (cnt);
     }
     }
-
-    /// @brief collection of subnet parsers.
-    ParserCollection subnets_;
 };
 };
 
 
 /// @brief Parser for list of RSOO options
 /// @brief Parser for list of RSOO options
@@ -664,8 +642,7 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id,
         (config_id.compare("dhcp4o6-port") == 0) )  {
         (config_id.compare("dhcp4o6-port") == 0) )  {
         parser = new Uint32Parser(config_id,
         parser = new Uint32Parser(config_id,
                                  globalContext()->uint32_values_);
                                  globalContext()->uint32_values_);
-    } else if (config_id.compare("subnet6") == 0) {
-        parser = new Subnets6ListConfigParser(config_id);
+    // subnet6 has been converted to SimpleParser.
     // option-data and option-def are no longer needed here. They're now
     // option-data and option-def are no longer needed here. They're now
     // converted to SimpleParser and are handled in configureDhcp6Server.
     // converted to SimpleParser and are handled in configureDhcp6Server.
     // interfaces-config has been converted to SimpleParser.
     // interfaces-config has been converted to SimpleParser.
@@ -796,7 +773,6 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
     // lease-database parser.
     // lease-database parser.
     // Please do not change this order!
     // Please do not change this order!
     ParserCollection independent_parsers;
     ParserCollection independent_parsers;
-    ParserPtr subnet_parser;
 
 
     // Some of the parsers alter state of the system that can't easily
     // Some of the parsers alter state of the system that can't easily
     // be undone. (Or alter it in a way such that undoing the change
     // be undone. (Or alter it in a way such that undoing the change
@@ -830,8 +806,12 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
         // default values and will insert derived values as well.
         // default values and will insert derived values as well.
         ElementPtr mutable_cfg = boost::const_pointer_cast<Element>(config_set);
         ElementPtr mutable_cfg = boost::const_pointer_cast<Element>(config_set);
 
 
+        // Set all default values if not specified by the user.
         SimpleParser6::setAllDefaults(mutable_cfg);
         SimpleParser6::setAllDefaults(mutable_cfg);
 
 
+        // And now derive (inherit) global parameters to subnets, if not specified.
+        SimpleParser6::deriveParameters(mutable_cfg);
+
         // Make parsers grouping.
         // Make parsers grouping.
         const std::map<std::string, ConstElementPtr>& values_map =
         const std::map<std::string, ConstElementPtr>& values_map =
             mutable_cfg->mapValue();
             mutable_cfg->mapValue();
@@ -942,30 +922,27 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
                 continue;
                 continue;
             }
             }
 
 
+            if (config_pair.first == "subnet6") {
+                SrvConfigPtr srv_cfg = CfgMgr::instance().getStagingCfg();
+                Subnets6ListConfigParser subnets_parser;
+                // parse() returns number of subnets parsed. We may log it one day.
+                subnets_parser.parse(srv_cfg, config_pair.second);
+                continue;
+            }
+
             ParserPtr parser(createGlobal6DhcpConfigParser(config_pair.first,
             ParserPtr parser(createGlobal6DhcpConfigParser(config_pair.first,
                                                            config_pair.second));
                                                            config_pair.second));
             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PARSER_CREATED)
             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PARSER_CREATED)
                       .arg(config_pair.first);
                       .arg(config_pair.first);
-            if (config_pair.first == "subnet6") {
-                subnet_parser = parser;
-            } else {
-                // Those parsers should be started before other
-                // parsers so we can call build straight away.
-                independent_parsers.push_back(parser);
-                parser->build(config_pair.second);
-                // The commit operation here may modify the global storage
-                // but we need it so as the subnet6 parser can access the
-                // parsed data.
-                parser->commit();
-            }
-        }
 
 
-        // The subnet parser is the next one to be run.
-        std::map<std::string, ConstElementPtr>::const_iterator subnet_config =
-            values_map.find("subnet6");
-        if (subnet_config != values_map.end()) {
-            config_pair.first = "subnet6";
-            subnet_parser->build(subnet_config->second);
+            // Those parsers should be started before other
+            // parsers so we can call build straight away.
+            independent_parsers.push_back(parser);
+            parser->build(config_pair.second);
+            // The commit operation here may modify the global storage
+            // but we need it so as the subnet6 parser can access the
+            // parsed data.
+            parser->commit();
         }
         }
 
 
         // Setup the command channel.
         // Setup the command channel.
@@ -993,9 +970,6 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
     // This operation should be exception safe but let's make sure.
     // This operation should be exception safe but let's make sure.
     if (!rollback) {
     if (!rollback) {
         try {
         try {
-            if (subnet_parser) {
-                subnet_parser->commit();
-            }
 
 
             // Apply global options in the staging config.
             // Apply global options in the staging config.
             setGlobalParameters6();
             setGlobalParameters6();

+ 14 - 0
src/bin/dhcp6/simple_parser6.cc

@@ -104,5 +104,19 @@ size_t SimpleParser6::setAllDefaults(isc::data::ElementPtr global) {
     return (cnt);
     return (cnt);
 }
 }
 
 
+size_t SimpleParser6::deriveParameters(isc::data::ElementPtr global) {
+    size_t cnt = 0;
+    // Now derive global parameters into subnets.
+    ConstElementPtr subnets = global->get("subnet6");
+    if (subnets) {
+        BOOST_FOREACH(ElementPtr single_subnet, subnets->listValue()) {
+            cnt += SimpleParser::deriveParams(global, single_subnet,
+                                              INHERIT_GLOBAL_TO_SUBNET6);
+        }
+    }
+
+    return (cnt);
+}
+
 };
 };
 };
 };

+ 8 - 0
src/bin/dhcp6/simple_parser6.h

@@ -29,6 +29,14 @@ public:
     /// @return number of default values added
     /// @return number of default values added
     static size_t setAllDefaults(isc::data::ElementPtr global);
     static size_t setAllDefaults(isc::data::ElementPtr global);
 
 
+    /// @brief Derives (inherits) all parameters from global to more specific scopes.
+    ///
+    /// This method currently does the following:
+    /// - derives global parameters to subnets (lifetimes for now)
+    /// @param global scope to be modified if needed (subnet4 will be extracted)
+    /// @return number of default values derived
+    static size_t deriveParameters(isc::data::ElementPtr global);
+
     // see simple_parser6.cc for comments for those parameters
     // see simple_parser6.cc for comments for those parameters
     static const isc::data::SimpleDefaults OPTION6_DEF_DEFAULTS;
     static const isc::data::SimpleDefaults OPTION6_DEF_DEFAULTS;
     static const isc::data::SimpleDefaults OPTION6_DEFAULTS;
     static const isc::data::SimpleDefaults OPTION6_DEFAULTS;

+ 7 - 3
src/bin/dhcp6/tests/simple_parser6_unittest.cc

@@ -67,14 +67,18 @@ TEST_F(SimpleParser6Test, inheritGlobalToSubnet6) {
                                           "  \"rebind-timer\": 2,"
                                           "  \"rebind-timer\": 2,"
                                           "  \"preferred-lifetime\": 3,"
                                           "  \"preferred-lifetime\": 3,"
                                           "  \"valid-lifetime\": 4"
                                           "  \"valid-lifetime\": 4"
+                                          "  \"subnet6\": [ { \"renew-timer\": 100 } ] "
                                           "}");
                                           "}");
-    ElementPtr subnet = parseJSON("{ \"renew-timer\": 100 }");
+
+    ConstElementPtr subnets = global->find("subnet6");
+    ASSERT_TRUE(subnets);
+    ConstElementPtr subnet = subnets->get(0);
+    ASSERT_TRUE(subnet);
 
 
     // we should inherit 3 parameters. Renew-timer should remain intact,
     // we should inherit 3 parameters. Renew-timer should remain intact,
     // as it was already defined in the subnet scope.
     // as it was already defined in the subnet scope.
     size_t num;
     size_t num;
-    EXPECT_NO_THROW(num = SimpleParser::deriveParams(global, subnet,
-                                                     SimpleParser6::INHERIT_GLOBAL_TO_SUBNET6));
+    EXPECT_NO_THROW(num = SimpleParser6::deriveParameters(global));
     EXPECT_EQ(3, num);
     EXPECT_EQ(3, num);
 
 
     // Check the values. 3 of them are inherited, while the fourth one
     // Check the values. 3 of them are inherited, while the fourth one

+ 3 - 1
src/lib/dhcpsrv/parsers/dhcp_parsers.cc

@@ -998,7 +998,7 @@ SubnetConfigParser::SubnetConfigParser(const std::string&,
 
 
 }
 }
 
 
-void
+SubnetPtr
 SubnetConfigParser::build(ConstElementPtr subnet) {
 SubnetConfigParser::build(ConstElementPtr subnet) {
     BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
     BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
         // Pools has been converted to SimpleParser.
         // Pools has been converted to SimpleParser.
@@ -1068,6 +1068,8 @@ SubnetConfigParser::build(ConstElementPtr subnet) {
                   "subnet configuration failed (" << subnet->getPosition()
                   "subnet configuration failed (" << subnet->getPosition()
                   << "): " << ex.what());
                   << "): " << ex.what());
     }
     }
+
+    return (subnet_);
 }
 }
 
 
 Subnet::HRMode
 Subnet::HRMode

+ 11 - 7
src/lib/dhcpsrv/parsers/dhcp_parsers.h

@@ -808,7 +808,7 @@ protected:
 ///
 ///
 /// This class parses the whole subnet definition. It creates parsers
 /// This class parses the whole subnet definition. It creates parsers
 /// for received configuration parameters as needed.
 /// for received configuration parameters as needed.
-class SubnetConfigParser : public DhcpConfigParser {
+class SubnetConfigParser : public isc::data::SimpleParser {
 public:
 public:
 
 
     /// @brief constructor
     /// @brief constructor
@@ -818,17 +818,21 @@ public:
     SubnetConfigParser(const std::string&, ParserContextPtr global_context,
     SubnetConfigParser(const std::string&, ParserContextPtr global_context,
                        const isc::asiolink::IOAddress& default_addr);
                        const isc::asiolink::IOAddress& default_addr);
 
 
-    /// @brief parses parameter value
+    /// @brief virtual destuctor (does nothing)
+    virtual ~SubnetConfigParser() { }
+
+protected:
+    /// @brief parses a subnet description and returns Subnet{4,6} structure
+    ///
+    /// This method is called from specialized (Subnet4ConfigParser or
+    /// Subnet6ConfigParser) classes.
     ///
     ///
     /// @param subnet pointer to the content of subnet definition
     /// @param subnet pointer to the content of subnet definition
+    /// @return a pointer to newly created subnet
     ///
     ///
     /// @throw isc::DhcpConfigError if subnet configuration parsing failed.
     /// @throw isc::DhcpConfigError if subnet configuration parsing failed.
-    virtual void build(isc::data::ConstElementPtr subnet);
+    virtual SubnetPtr build(isc::data::ConstElementPtr subnet);
 
 
-    /// @brief Adds the created subnet to a server's configuration.
-    virtual void commit() = 0;
-
-protected:
     /// @brief creates parsers for entries in subnet definition
     /// @brief creates parsers for entries in subnet definition
     ///
     ///
     /// @param config_id name of the entry
     /// @param config_id name of the entry