Browse Source

[2544] Add options to s subnet when configured.

Marcin Siodelski 12 years ago
parent
commit
079e629bde
2 changed files with 87 additions and 26 deletions
  1. 82 26
      src/bin/dhcp4/config_parser.cc
  2. 5 0
      src/bin/dhcp4/dhcp4_messages.mes

+ 82 - 26
src/bin/dhcp4/config_parser.cc

@@ -819,35 +819,36 @@ public:
     void build(ConstElementPtr subnet) {
     void build(ConstElementPtr subnet) {
 
 
         BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
         BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
-
             ParserPtr parser(createSubnet4ConfigParser(param.first));
             ParserPtr parser(createSubnet4ConfigParser(param.first));
-
-            // if this is an Uint32 parser, tell it to store the values
-            // in values_, rather than in global storage
-            boost::shared_ptr<Uint32Parser> uint_parser =
-                boost::dynamic_pointer_cast<Uint32Parser>(parser);
-            if (uint_parser) {
-                uint_parser->setStorage(&uint32_values_);
-            } else {
-
-                boost::shared_ptr<StringParser> string_parser =
-                    boost::dynamic_pointer_cast<StringParser>(parser);
-                if (string_parser) {
-                    string_parser->setStorage(&string_values_);
-                } else {
-
-                    boost::shared_ptr<PoolParser> pool_parser =
-                        boost::dynamic_pointer_cast<PoolParser>(parser);
-                    if (pool_parser) {
-                        pool_parser->setStorage(&pools_);
-                    }
-                }
+            // The actual type of the parser is unknown here. We have to discover
+            // the parser type here to invoke the corresponding setStorage function
+            // on it.  We discover parser type by trying to cast the parser to various
+            // parser types and checking which one was successful. For this one
+            // a setStorage and build methods are invoked.
+
+            // Try uint32 type parser.
+            if (buildParser<Uint32Parser, Uint32Storage >(parser, uint32_values_,
+                                                          param.second)) {
+                // Storage set, build invoked on the parser, proceed with
+                // next configuration element.
+                continue;
+            }
+            // Try string type parser.
+            if (buildParser<StringParser, StringStorage >(parser, string_values_,
+                                                          param.second)) {
+                continue;
+            }
+            // Try pools parser.
+            if (buildParser<PoolParser, PoolStorage >(parser, pools_,
+                                                      param.second)) {
+                continue;
+            }
+            // Try option data parser.
+            if (buildParser<OptionDataListParser, OptionStorage >(parser, options_,
+                                                                  param.second)) {
+                continue;
             }
             }
-
-            parser->build(param.second);
-            parsers_.push_back(parser);
         }
         }
-
         // Ok, we now have subnet parsed
         // Ok, we now have subnet parsed
     }
     }
 
 
@@ -859,6 +860,10 @@ public:
     /// objects. Subnet4 are then added to DHCP CfgMgr.
     /// objects. Subnet4 are then added to DHCP CfgMgr.
     /// @throw Dhcp4ConfigError if there are any issues encountered during commit
     /// @throw Dhcp4ConfigError if there are any issues encountered during commit
     void commit() {
     void commit() {
+        // Invoke commit on all sub-data parsers.
+        BOOST_FOREACH(ParserPtr parser, parsers_) {
+            parser->commit();
+        }
 
 
         StringStorage::const_iterator it = string_values_.find("subnet");
         StringStorage::const_iterator it = string_values_.find("subnet");
         if (it == string_values_.end()) {
         if (it == string_values_.end()) {
@@ -894,11 +899,58 @@ public:
             subnet->addPool4(*it);
             subnet->addPool4(*it);
         }
         }
 
 
+        const Subnet::OptionContainer& options = subnet->getOptions();
+        const Subnet::OptionContainerTypeIndex& idx = options.get<1>();
+
+        // Add subnet specific options.
+        BOOST_FOREACH(Subnet::OptionDescriptor desc, options_) {
+            Subnet::OptionContainerTypeRange range = idx.equal_range(desc.option->getType());
+            if (std::distance(range.first, range.second) > 0) {
+                LOG_WARN(dhcp4_logger, DHCP4_CONFIG_OPTION_DUPLICATE)
+                    .arg(desc.option->getType()).arg(addr.toText());
+            }
+            subnet->addOption(desc.option);
+        }
+
         CfgMgr::instance().addSubnet4(subnet);
         CfgMgr::instance().addSubnet4(subnet);
     }
     }
 
 
 private:
 private:
 
 
+    /// @brief Set storage for a parser and invoke build.
+    ///
+    /// This helper method casts the provided parser pointer to the specified
+    /// type. If the cast is successful it sets the corresponding storage for
+    /// this parser, invokes build on it and saves the parser.
+    ///
+    /// @tparam T parser type to which parser argument should be cast.
+    /// @tparam Y storage type for the specified parser type.
+    /// @param parser parser on which build must be invoked.
+    /// @param storage reference to a storage that will be set for a parser.
+    /// @param subnet subnet element read from the configuration and being parsed.
+    /// @return true if parser pointer was successfully cast to specialized
+    /// parser type provided as Y.
+    template<typename T, typename Y>
+    bool buildParser(const ParserPtr& parser, Y& storage, const ConstElementPtr& subnet) {
+        // We need to cast to T in order to set storage for the parser.
+        boost::shared_ptr<T> cast_parser = boost::dynamic_pointer_cast<T>(parser);
+        // It is common that this cast is not successful because we try to cast to all
+        // supported parser types as we don't know the type of a parser in advance.
+        if (cast_parser) {
+            // Cast, successful so we go ahead with setting storage and actual parse.
+            cast_parser->setStorage(&storage);
+            parser->build(subnet);
+            parsers_.push_back(parser);
+            // We indicate that cast was successful so as the calling function
+            // may skip attempts to cast to other parser types and proceed to
+            // next element.
+            return (true);
+        }
+        // It was not successful. Indicate that another parser type
+        // should be tried.
+        return (false);
+    }
+
     /// @brief creates parsers for entries in subnet definition
     /// @brief creates parsers for entries in subnet definition
     ///
     ///
     /// @todo Add subnet-specific things here (e.g. subnet-specific options)
     /// @todo Add subnet-specific things here (e.g. subnet-specific options)
@@ -969,6 +1021,9 @@ private:
     /// storage for pools belonging to this subnet
     /// storage for pools belonging to this subnet
     PoolStorage pools_;
     PoolStorage pools_;
 
 
+    /// storage for options belonging to this subnet
+    OptionStorage options_;
+
     /// parsers are stored here
     /// parsers are stored here
     ParserCollection parsers_;
     ParserCollection parsers_;
 };
 };
@@ -1051,6 +1106,7 @@ Dhcp4ConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
     factories["rebind-timer"] = Uint32Parser::Factory;
     factories["rebind-timer"] = Uint32Parser::Factory;
     factories["interface"] = InterfaceListConfigParser::Factory;
     factories["interface"] = InterfaceListConfigParser::Factory;
     factories["subnet4"] = Subnets4ListConfigParser::Factory;
     factories["subnet4"] = Subnets4ListConfigParser::Factory;
+    factories["option-data"] = OptionDataListParser::Factory;
     factories["version"] = StringParser::Factory;
     factories["version"] = StringParser::Factory;
 
 
     FactoryMap::iterator f = factories.find(config_id);
     FactoryMap::iterator f = factories.find(config_id);

+ 5 - 0
src/bin/dhcp4/dhcp4_messages.mes

@@ -44,6 +44,11 @@ change is committed by the administrator.
 This is an informational message reporting that the configuration has
 This is an informational message reporting that the configuration has
 been extended to include the specified IPv4 subnet.
 been extended to include the specified IPv4 subnet.
 
 
+% DHCP4_CONFIG_OPTION_DUPLICATE multiple options with the code: %1 added to the subnet: %2
+This warning message is issued on attempt to configure multiple options with the
+same option code for the particular subnet. Adding multiple options is uncommon
+for DHCPv4, yet it is not prohibited.
+
 % DHCP4_CONFIG_COMPLETE DHCPv4 server has completed configuration: %1
 % DHCP4_CONFIG_COMPLETE DHCPv4 server has completed configuration: %1
 This is an informational message announcing the successful processing of a
 This is an informational message announcing the successful processing of a
 new configuration. it is output during server startup, and when an updated
 new configuration. it is output during server startup, and when an updated