|
@@ -1,4 +1,4 @@
|
|
-// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
|
|
|
|
|
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
|
//
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
@@ -21,6 +21,7 @@
|
|
#include <boost/scoped_ptr.hpp>
|
|
#include <boost/scoped_ptr.hpp>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/algorithm/string.hpp>
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
+#include <util/encode/hex.h>
|
|
#include <asiolink/io_address.h>
|
|
#include <asiolink/io_address.h>
|
|
#include <cc/data.h>
|
|
#include <cc/data.h>
|
|
#include <config/ccsession.h>
|
|
#include <config/ccsession.h>
|
|
@@ -60,12 +61,18 @@ typedef std::map<string, string> StringStorage;
|
|
/// no subnet object created yet to store them.
|
|
/// no subnet object created yet to store them.
|
|
typedef std::vector<Pool6Ptr> PoolStorage;
|
|
typedef std::vector<Pool6Ptr> PoolStorage;
|
|
|
|
|
|
|
|
+/// @brief Collection of options.
|
|
|
|
+typedef std::vector<OptionPtr> OptionStorage;
|
|
|
|
+
|
|
/// @brief Global uint32 parameters that will be used as defaults.
|
|
/// @brief Global uint32 parameters that will be used as defaults.
|
|
Uint32Storage uint32_defaults;
|
|
Uint32Storage uint32_defaults;
|
|
|
|
|
|
/// @brief global string parameters that will be used as defaults.
|
|
/// @brief global string parameters that will be used as defaults.
|
|
StringStorage string_defaults;
|
|
StringStorage string_defaults;
|
|
|
|
|
|
|
|
+/// @brief Global storage for options that will be used as defaults.
|
|
|
|
+OptionStorage option_defaults;
|
|
|
|
+
|
|
/// @brief a dummy configuration parser
|
|
/// @brief a dummy configuration parser
|
|
///
|
|
///
|
|
/// It is a debugging parser. It does not configure anything,
|
|
/// It is a debugging parser. It does not configure anything,
|
|
@@ -135,6 +142,9 @@ protected:
|
|
///
|
|
///
|
|
/// For overview of usability of this generic purpose parser, see
|
|
/// For overview of usability of this generic purpose parser, see
|
|
/// \ref dhcpv6-config-inherit page.
|
|
/// \ref dhcpv6-config-inherit page.
|
|
|
|
+///
|
|
|
|
+/// @todo this class should be turned into the template class which
|
|
|
|
+/// will handle all uintX_types of data (see ticket #2415).
|
|
class Uint32Parser : public DhcpConfigParser {
|
|
class Uint32Parser : public DhcpConfigParser {
|
|
public:
|
|
public:
|
|
|
|
|
|
@@ -151,12 +161,37 @@ public:
|
|
///
|
|
///
|
|
/// @param value pointer to the content of parsed values
|
|
/// @param value pointer to the content of parsed values
|
|
virtual void build(ConstElementPtr value) {
|
|
virtual void build(ConstElementPtr value) {
|
|
|
|
+ bool parse_error = false;
|
|
|
|
+ // Cast the provided value to int64 value to check.
|
|
|
|
+ int64_t int64value = 0;
|
|
try {
|
|
try {
|
|
- value_ = boost::lexical_cast<uint32_t>(value->str());
|
|
|
|
- } catch (const boost::bad_lexical_cast &) {
|
|
|
|
|
|
+ // Parsing the value as a int64 value allows to
|
|
|
|
+ // check if the provided value is within the range
|
|
|
|
+ // of uint32_t (is not negative or greater than
|
|
|
|
+ // maximal uint32_t value.
|
|
|
|
+ int64value = boost::lexical_cast<int64_t>(value->str());
|
|
|
|
+ } catch (const boost::bad_lexical_cast&) {
|
|
|
|
+ parse_error = true;
|
|
|
|
+ }
|
|
|
|
+ if (!parse_error) {
|
|
|
|
+ if ((int64value < 0) ||
|
|
|
|
+ (int64value > std::numeric_limits<uint32_t>::max())) {
|
|
|
|
+ parse_error = true;
|
|
|
|
+ } else {
|
|
|
|
+ try {
|
|
|
|
+ value_ = boost::lexical_cast<uint32_t>(value->str());
|
|
|
|
+ } catch (const boost::bad_lexical_cast &) {
|
|
|
|
+ parse_error = true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (parse_error) {
|
|
isc_throw(BadValue, "Failed to parse value " << value->str()
|
|
isc_throw(BadValue, "Failed to parse value " << value->str()
|
|
<< " as unsigned 32-bit integer.");
|
|
<< " as unsigned 32-bit integer.");
|
|
}
|
|
}
|
|
|
|
+
|
|
storage_->insert(pair<string, uint32_t>(param_name_, value_));
|
|
storage_->insert(pair<string, uint32_t>(param_name_, value_));
|
|
}
|
|
}
|
|
|
|
|
|
@@ -445,6 +480,259 @@ protected:
|
|
PoolStorage* pools_;
|
|
PoolStorage* pools_;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+/// @brief Parser for option data value.
|
|
|
|
+///
|
|
|
|
+/// This parser parses configuration entries that specify value of
|
|
|
|
+/// a single option. These entries include option name, option code
|
|
|
|
+/// and data carried by the option. If parsing is successful than
|
|
|
|
+/// instance of an option is created and added to the storage provided
|
|
|
|
+/// by the calling class.
|
|
|
|
+///
|
|
|
|
+/// @todo This class parses and validates option name. However it is
|
|
|
|
+/// not used anywhere util support for option spaces is implemented
|
|
|
|
+/// (see tickets #2319, #2314). When option spaces are implemented
|
|
|
|
+/// there will be a way to reference the particular option using
|
|
|
|
+/// its type (code) or option name.
|
|
|
|
+class OptionDataParser : public DhcpConfigParser {
|
|
|
|
+public:
|
|
|
|
+
|
|
|
|
+ /// @brief Constructor.
|
|
|
|
+ ///
|
|
|
|
+ /// Class constructor.
|
|
|
|
+ OptionDataParser(const std::string&)
|
|
|
|
+ : options_(NULL) { }
|
|
|
|
+
|
|
|
|
+ /// @brief Parses the single option data.
|
|
|
|
+ ///
|
|
|
|
+ /// This method parses the data of a single option from the configuration.
|
|
|
|
+ /// The option data includes option name, option code and data being
|
|
|
|
+ /// carried by this option. Eventually it creates the instance of the
|
|
|
|
+ /// option.
|
|
|
|
+ ///
|
|
|
|
+ /// @warning setStorage must be called with valid storage pointer prior
|
|
|
|
+ /// to calling this method.
|
|
|
|
+ ///
|
|
|
|
+ /// @param option_data_entries collection of entries that define value
|
|
|
|
+ /// for a particular option.
|
|
|
|
+ /// @throw Dhcp6ConfigError if invalid parameter specified in
|
|
|
|
+ /// the configuration.
|
|
|
|
+ /// @throw isc::InvalidOperation if failed to set storage prior to
|
|
|
|
+ /// calling build.
|
|
|
|
+ /// @throw isc::BadValue if option data storage is invalid.
|
|
|
|
+ virtual void build(ConstElementPtr option_data_entries) {
|
|
|
|
+ if (options_ == NULL) {
|
|
|
|
+ isc_throw(isc::InvalidOperation, "Parser logic error: storage must be set before "
|
|
|
|
+ "parsing option data.");
|
|
|
|
+ }
|
|
|
|
+ BOOST_FOREACH(ConfigPair param, option_data_entries->mapValue()) {
|
|
|
|
+ ParserPtr parser;
|
|
|
|
+ if (param.first == "name") {
|
|
|
|
+ boost::shared_ptr<StringParser>
|
|
|
|
+ name_parser(dynamic_cast<StringParser*>(StringParser::Factory(param.first)));
|
|
|
|
+ if (name_parser) {
|
|
|
|
+ name_parser->setStorage(&string_values_);
|
|
|
|
+ parser = name_parser;
|
|
|
|
+ }
|
|
|
|
+ } else if (param.first == "code") {
|
|
|
|
+ boost::shared_ptr<Uint32Parser>
|
|
|
|
+ code_parser(dynamic_cast<Uint32Parser*>(Uint32Parser::Factory(param.first)));
|
|
|
|
+ if (code_parser) {
|
|
|
|
+ code_parser->setStorage(&uint32_values_);
|
|
|
|
+ parser = code_parser;
|
|
|
|
+ }
|
|
|
|
+ } else if (param.first == "data") {
|
|
|
|
+ boost::shared_ptr<StringParser>
|
|
|
|
+ value_parser(dynamic_cast<StringParser*>(StringParser::Factory(param.first)));
|
|
|
|
+ if (value_parser) {
|
|
|
|
+ value_parser->setStorage(&string_values_);
|
|
|
|
+ parser = value_parser;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ isc_throw(Dhcp6ConfigError,
|
|
|
|
+ "Parser error: option-data parameter not supported: "
|
|
|
|
+ << param.first);
|
|
|
|
+ }
|
|
|
|
+ parser->build(param.second);
|
|
|
|
+ }
|
|
|
|
+ // Try to create the option instance.
|
|
|
|
+ createOption();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// @brief Does nothing.
|
|
|
|
+ ///
|
|
|
|
+ /// This function does noting because option data is committed
|
|
|
|
+ /// by a higher level parser.
|
|
|
|
+ virtual void commit() { }
|
|
|
|
+
|
|
|
|
+ /// @brief Set storage for the parser.
|
|
|
|
+ ///
|
|
|
|
+ /// Sets storage for the parser. This storage points to the
|
|
|
|
+ /// vector of options and is used by multiple instances of
|
|
|
|
+ /// OptionDataParser. Each instance creates exactly one object
|
|
|
|
+ /// of dhcp::Option or derived type and appends it to this
|
|
|
|
+ /// storage.
|
|
|
|
+ ///
|
|
|
|
+ /// @param storage pointer to the options storage
|
|
|
|
+ void setStorage(OptionStorage* storage) {
|
|
|
|
+ options_ = storage;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+private:
|
|
|
|
+
|
|
|
|
+ /// @brief Create option instance.
|
|
|
|
+ ///
|
|
|
|
+ /// Creates an instance of an option and adds it to the provided
|
|
|
|
+ /// options storage. If the option data parsed by \ref build function
|
|
|
|
+ /// are invalid or insufficient it emits exception.
|
|
|
|
+ ///
|
|
|
|
+ /// @warning this function does not check if options_ storage pointer
|
|
|
|
+ /// is intitialized but this is not needed here because it is checked in
|
|
|
|
+ /// \ref build function.
|
|
|
|
+ ///
|
|
|
|
+ /// @throw Dhcp6ConfigError if parameters provided in the configuration
|
|
|
|
+ /// are invalid.
|
|
|
|
+ void createOption() {
|
|
|
|
+ // Option code is held in the uint32_t storage but is supposed to
|
|
|
|
+ // be uint16_t value. We need to check that value in the configuration
|
|
|
|
+ // does not exceed range of uint16_t and is not zero.
|
|
|
|
+ uint32_t option_code = getUint32Param("code");
|
|
|
|
+ if (option_code == 0) {
|
|
|
|
+ isc_throw(Dhcp6ConfigError, "Parser error: value of 'code' must not"
|
|
|
|
+ << " be equal to zero. Option code '0' is reserved in"
|
|
|
|
+ << " DHCPv6.");
|
|
|
|
+ } else if (option_code > std::numeric_limits<uint16_t>::max()) {
|
|
|
|
+ isc_throw(Dhcp6ConfigError, "Parser error: value of 'code' must not"
|
|
|
|
+ << " exceed " << std::numeric_limits<uint16_t>::max());
|
|
|
|
+ }
|
|
|
|
+ // Check the option name has been specified, is non-empty and does not
|
|
|
|
+ // contain spaces.
|
|
|
|
+ // @todo possibly some more restrictions apply here?
|
|
|
|
+ std::string option_name = getStringParam("name");
|
|
|
|
+ if (option_name.empty()) {
|
|
|
|
+ isc_throw(Dhcp6ConfigError, "Parser error: option name must not be"
|
|
|
|
+ << " empty");
|
|
|
|
+ } else if (option_name.find(" ") != std::string::npos) {
|
|
|
|
+ isc_throw(Dhcp6ConfigError, "Parser error: option name must not contain"
|
|
|
|
+ << " spaces");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ std::string option_data = getStringParam("data");
|
|
|
|
+ std::vector<uint8_t> binary;
|
|
|
|
+ try {
|
|
|
|
+ util::encode::decodeHex(option_data, binary);
|
|
|
|
+ } catch (...) {
|
|
|
|
+ isc_throw(Dhcp6ConfigError, "Parser error: option data is not a valid"
|
|
|
|
+ << " string of hexadecimal digits: " << option_data);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Create the actual option.
|
|
|
|
+ // @todo Currently we simply create dhcp::Option instance here but we will
|
|
|
|
+ // need to use dedicated factory functions once the option definitions are
|
|
|
|
+ // created for all options.
|
|
|
|
+ OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
|
|
|
|
+ binary));
|
|
|
|
+
|
|
|
|
+ // If option is created succesfully, add it to the storage.
|
|
|
|
+ options_->push_back(option);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// @brief Get a parameter from the strings storage.
|
|
|
|
+ ///
|
|
|
|
+ /// @param param_id parameter identifier.
|
|
|
|
+ /// @throw Dhcp6ConfigError if parameter has not been found.
|
|
|
|
+ std::string getStringParam(const std::string& param_id) const {
|
|
|
|
+ StringStorage::const_iterator param = string_values_.find(param_id);
|
|
|
|
+ if (param == string_values_.end()) {
|
|
|
|
+ isc_throw(Dhcp6ConfigError, "Parser error: option-data parameter"
|
|
|
|
+ << " '" << param_id << "' not specified");
|
|
|
|
+ }
|
|
|
|
+ return (param->second);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// @brief Get a parameter from the uint32 values storage.
|
|
|
|
+ ///
|
|
|
|
+ /// @param param_id parameter identifier.
|
|
|
|
+ /// @throw Dhcp6ConfigError if parameter has not been found.
|
|
|
|
+ uint32_t getUint32Param(const std::string& param_id) const {
|
|
|
|
+ Uint32Storage::const_iterator param = uint32_values_.find(param_id);
|
|
|
|
+ if (param == uint32_values_.end()) {
|
|
|
|
+ isc_throw(Dhcp6ConfigError, "Parser error: option-data parameter"
|
|
|
|
+ << " '" << param_id << "' not specified");
|
|
|
|
+ }
|
|
|
|
+ return (param->second);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Storage for uint32 values (e.g. option code).
|
|
|
|
+ Uint32Storage uint32_values_;
|
|
|
|
+ /// Storage for string values (e.g. option name or data).
|
|
|
|
+ StringStorage string_values_;
|
|
|
|
+ /// Pointer to options storage. This storage is provided by
|
|
|
|
+ /// the calling class and is shared by all OptionDataParser objects.
|
|
|
|
+ OptionStorage* options_;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/// @brief Parser for option data values with ina subnet.
|
|
|
|
+///
|
|
|
|
+/// This parser iterates over all entries that define options
|
|
|
|
+/// data for a particular subnet and creates a collection of options.
|
|
|
|
+/// If parsing is successful, all these options are added to the Subnet
|
|
|
|
+/// object.
|
|
|
|
+class OptionDataListParser : public DhcpConfigParser {
|
|
|
|
+public:
|
|
|
|
+
|
|
|
|
+ /// @brief Constructor.
|
|
|
|
+ ///
|
|
|
|
+ /// Unless otherwise specified, parsed options will be stored in
|
|
|
|
+ /// a global option containers (option_default). That storage location
|
|
|
|
+ /// is overriden on a subnet basis.
|
|
|
|
+ OptionDataListParser(const std::string&)
|
|
|
|
+ : options_(&option_defaults) { }
|
|
|
|
+
|
|
|
|
+ /// @brief Parses entries that define options' data for a subnet.
|
|
|
|
+ ///
|
|
|
|
+ /// This method iterates over all entries that define option data
|
|
|
|
+ /// for options within a single subnet and creates options' instances.
|
|
|
|
+ ///
|
|
|
|
+ /// @param option_data_list pointer to a list of options' data sets.
|
|
|
|
+ /// @throw Dhcp6ConfigError if option parsing failed.
|
|
|
|
+ void build(ConstElementPtr option_data_list) {
|
|
|
|
+ BOOST_FOREACH(ConstElementPtr option_value, option_data_list->listValue()) {
|
|
|
|
+ boost::shared_ptr<OptionDataParser> parser(new OptionDataParser("option-data"));
|
|
|
|
+ // options_ member will hold instances of all options thus
|
|
|
|
+ // each OptionDataParser takes it as a storage.
|
|
|
|
+ parser->setStorage(options_);
|
|
|
|
+ // Build the instance of a singkle option.
|
|
|
|
+ parser->build(option_value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// @brief Set storage for option instances.
|
|
|
|
+ ///
|
|
|
|
+ /// @param storage pointer to options storage.
|
|
|
|
+ void setStorage(OptionStorage* storage) {
|
|
|
|
+ options_ = storage;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /// @brief Does nothing.
|
|
|
|
+ ///
|
|
|
|
+ /// @todo Currently this function does nothing but in the future
|
|
|
|
+ /// we may need to extend it to commit at this level.
|
|
|
|
+ void commit() { }
|
|
|
|
+
|
|
|
|
+ /// @brief Create DhcpDataListParser object
|
|
|
|
+ ///
|
|
|
|
+ /// @param param_name param name.
|
|
|
|
+ ///
|
|
|
|
+ /// @return DhcpConfigParser object.
|
|
|
|
+ static DhcpConfigParser* Factory(const std::string& param_name) {
|
|
|
|
+ return (new OptionDataListParser(param_name));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Pointer to options instances storage.
|
|
|
|
+ OptionStorage* options_;
|
|
|
|
+};
|
|
|
|
+
|
|
/// @brief this class parses a single subnet
|
|
/// @brief this class parses a single subnet
|
|
///
|
|
///
|
|
/// This class parses the whole subnet definition. It creates parsers
|
|
/// This class parses the whole subnet definition. It creates parsers
|
|
@@ -464,35 +752,36 @@ public:
|
|
void build(ConstElementPtr subnet) {
|
|
void build(ConstElementPtr subnet) {
|
|
|
|
|
|
BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
|
|
BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
|
|
-
|
|
|
|
ParserPtr parser(createSubnet6ConfigParser(param.first));
|
|
ParserPtr parser(createSubnet6ConfigParser(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> uintParser =
|
|
|
|
- boost::dynamic_pointer_cast<Uint32Parser>(parser);
|
|
|
|
- if (uintParser) {
|
|
|
|
- uintParser->setStorage(&uint32_values_);
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- boost::shared_ptr<StringParser> stringParser =
|
|
|
|
- boost::dynamic_pointer_cast<StringParser>(parser);
|
|
|
|
- if (stringParser) {
|
|
|
|
- stringParser->setStorage(&string_values_);
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- boost::shared_ptr<PoolParser> poolParser =
|
|
|
|
- boost::dynamic_pointer_cast<PoolParser>(parser);
|
|
|
|
- if (poolParser) {
|
|
|
|
- poolParser->setStorage(&pools_);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ // The actual type of the parser is unknown here. We have to discover
|
|
|
|
+ // parser type here to invoke 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
|
|
}
|
|
}
|
|
|
|
|
|
@@ -540,10 +829,78 @@ public:
|
|
subnet->addPool6(*it);
|
|
subnet->addPool6(*it);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ const Subnet::OptionContainer& options = subnet->getOptions();
|
|
|
|
+ const Subnet::OptionContainerTypeIndex& idx = options.get<1>();
|
|
|
|
+
|
|
|
|
+ // Add subnet specific options.
|
|
|
|
+ BOOST_FOREACH(OptionPtr option, options_) {
|
|
|
|
+ Subnet::OptionContainerTypeRange range = idx.equal_range(option->getType());
|
|
|
|
+ if (std::distance(range.first, range.second) > 0) {
|
|
|
|
+ LOG_WARN(dhcp6_logger, DHCP6_CONFIG_OPTION_DUPLICATE)
|
|
|
|
+ .arg(option->getType()).arg(addr.toText());
|
|
|
|
+ }
|
|
|
|
+ subnet->addOption(option);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Check all global options and add them to the subnet object if
|
|
|
|
+ // they have been configured in the global scope. If they have been
|
|
|
|
+ // configured in the subnet scope we don't add global option because
|
|
|
|
+ // the one configured in the subnet scope always takes precedense.
|
|
|
|
+ BOOST_FOREACH(OptionPtr option, option_defaults) {
|
|
|
|
+ // Get all options specified locally in the subnet and having
|
|
|
|
+ // code equal to global option's code.
|
|
|
|
+ Subnet::OptionContainerTypeRange range = idx.equal_range(option->getType());
|
|
|
|
+ // @todo: In the future we will be searching for options using either
|
|
|
|
+ // option code or namespace. Currently we have only the option
|
|
|
|
+ // code available so if there is at least one option found with the
|
|
|
|
+ // specific code we don't add globally configured option.
|
|
|
|
+ // @todo with this code the first globally configured option
|
|
|
|
+ // with the given code will be added to a subnet. We may
|
|
|
|
+ // want to issue warning about dropping configuration of
|
|
|
|
+ // global option if one already exsist.
|
|
|
|
+ if (std::distance(range.first, range.second) == 0) {
|
|
|
|
+ subnet->addOption(option);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
CfgMgr::instance().addSubnet6(subnet);
|
|
CfgMgr::instance().addSubnet6(subnet);
|
|
}
|
|
}
|
|
|
|
|
|
-protected:
|
|
|
|
|
|
+private:
|
|
|
|
+
|
|
|
|
+ /// @brief Set storage for a parser and invoke build.
|
|
|
|
+ ///
|
|
|
|
+ /// This helper method casts the provided parser pointer to specified
|
|
|
|
+ /// type. If cast is successful it sets the corresponding storage for
|
|
|
|
+ /// this parser, invokes build on it and save 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
|
|
///
|
|
///
|
|
@@ -569,6 +926,10 @@ protected:
|
|
factories.insert(pair<string, ParserFactory*>(
|
|
factories.insert(pair<string, ParserFactory*>(
|
|
"pool", PoolParser::Factory));
|
|
"pool", PoolParser::Factory));
|
|
|
|
|
|
|
|
+ factories.insert(pair<string, ParserFactory*>(
|
|
|
|
+ "option-data", OptionDataListParser::Factory));
|
|
|
|
+
|
|
|
|
+
|
|
FactoryMap::iterator f = factories.find(config_id);
|
|
FactoryMap::iterator f = factories.find(config_id);
|
|
if (f == factories.end()) {
|
|
if (f == factories.end()) {
|
|
// Used for debugging only.
|
|
// Used for debugging only.
|
|
@@ -622,6 +983,9 @@ protected:
|
|
/// 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_;
|
|
};
|
|
};
|
|
@@ -698,7 +1062,6 @@ public:
|
|
DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
|
|
DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
|
|
FactoryMap factories;
|
|
FactoryMap factories;
|
|
|
|
|
|
- //
|
|
|
|
factories.insert(pair<string, ParserFactory*>(
|
|
factories.insert(pair<string, ParserFactory*>(
|
|
"preferred-lifetime", Uint32Parser::Factory));
|
|
"preferred-lifetime", Uint32Parser::Factory));
|
|
factories.insert(pair<string, ParserFactory*>(
|
|
factories.insert(pair<string, ParserFactory*>(
|
|
@@ -714,6 +1077,9 @@ DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
|
|
"subnet6", Subnets6ListConfigParser::Factory));
|
|
"subnet6", Subnets6ListConfigParser::Factory));
|
|
|
|
|
|
factories.insert(pair<string, ParserFactory*>(
|
|
factories.insert(pair<string, ParserFactory*>(
|
|
|
|
+ "option-data", OptionDataListParser::Factory));
|
|
|
|
+
|
|
|
|
+ factories.insert(pair<string, ParserFactory*>(
|
|
"version", StringParser::Factory));
|
|
"version", StringParser::Factory));
|
|
|
|
|
|
FactoryMap::iterator f = factories.find(config_id);
|
|
FactoryMap::iterator f = factories.find(config_id);
|
|
@@ -749,6 +1115,12 @@ configureDhcp6Server(Dhcpv6Srv& , ConstElementPtr config_set) {
|
|
"Null pointer is passed to configuration parser");
|
|
"Null pointer is passed to configuration parser");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// Reset global storage. Containers being reset below may contain
|
|
|
|
+ /// data from the previous configuration attempts.
|
|
|
|
+ option_defaults.clear();
|
|
|
|
+ uint32_defaults.clear();
|
|
|
|
+ string_defaults.clear();
|
|
|
|
+
|
|
/// @todo: append most essential info here (like "2 new subnets configured")
|
|
/// @todo: append most essential info here (like "2 new subnets configured")
|
|
string config_details;
|
|
string config_details;
|
|
|
|
|