From 3e674fdaf2fd78f588a9155cb2e955723259b4fd Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Thu, 12 Jan 2017 01:14:50 +0100 Subject: [PATCH] [5097] Migrated (checkpoint as user-context are missing in flex/bison) --- src/bin/dhcp4/json_config_parser.cc | 43 +++-- src/bin/dhcp6/json_config_parser.cc | 219 ++++++++++-------------- src/lib/dhcpsrv/parsers/dhcp_parsers.cc | 83 +++------ src/lib/dhcpsrv/parsers/dhcp_parsers.h | 76 +++----- 4 files changed, 163 insertions(+), 258 deletions(-) diff --git a/src/bin/dhcp4/json_config_parser.cc b/src/bin/dhcp4/json_config_parser.cc index c710f0b674..9ed084bb91 100644 --- a/src/bin/dhcp4/json_config_parser.cc +++ b/src/bin/dhcp4/json_config_parser.cc @@ -58,12 +58,8 @@ public: /// @brief Constructor. /// - /// @param param_name name of the parameter. Note, it is passed through - /// but unused, parameter is currently always "Dhcp4/subnet4[X]/pool" - /// @param pools storage container in which to store the parsed pool - /// upon "commit" - Pool4Parser(const std::string& param_name, PoolStoragePtr pools) - :PoolParser(param_name, pools, AF_INET) { + /// @param pools storage container in which to store the parsed pool. + Pool4Parser(PoolStoragePtr pools) : PoolParser(pools) { } protected: @@ -90,15 +86,26 @@ protected: } }; -class Pools4ListParser : public PoolsListParser { +/// @brief Specialization of the pool list parser for DHCPv4 +class Pools4ListParser : PoolsListParser { public: - Pools4ListParser(const std::string& dummy, PoolStoragePtr pools) - :PoolsListParser(dummy, pools) { + /// @brief Constructor. + /// + /// @param pools storage container in which to store the parsed pool. + Pools4ListParser(PoolStoragePtr pools) : PoolsListParser(pools) { } -protected: - virtual ParserPtr poolParserMaker(PoolStoragePtr storage) { - return (ParserPtr(new Pool4Parser("pool", storage))); + /// @brief parses the actual structure + /// + /// This method parses the actual list of pools. + /// + /// @param pools_list a list of pool structures + /// @throw isc::dhcp::DhcpConfigError when pool parsing fails + void parse(isc::data::ConstElementPtr pools_list) { + BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) { + Pool4Parser parser(pools_); + parser.parse(pool, AF_INET); + } } }; @@ -123,6 +130,13 @@ public: /// /// @param subnet A new subnet being configured. void build(ConstElementPtr subnet) { + /// Parse Pools first. + ConstElementPtr pools = subnet->get("pools"); + if (pools) { + Pools4ListParser parser(pools_); + parser.parse(pools); + } + SubnetConfigParser::build(subnet); if (subnet_) { @@ -186,9 +200,8 @@ protected: (config_id.compare("next-server") == 0) || (config_id.compare("reservation-mode") == 0)) { parser = new StringParser(config_id, string_values_); - } else if (config_id.compare("pools") == 0) { - parser = new Pools4ListParser(config_id, pools_); - // relay has been converted to SimpleParser already. + // pools has been converted to SimpleParser already. + // relay has been converted to SimpleParser already. // option-data has been converted to SimpleParser already. } else if (config_id.compare("match-client-id") == 0) { parser = new BooleanParser(config_id, boolean_values_); diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc index 68af31fd37..bf913f5012 100644 --- a/src/bin/dhcp6/json_config_parser.cc +++ b/src/bin/dhcp6/json_config_parser.cc @@ -75,12 +75,8 @@ public: /// @brief Constructor. /// - /// @param param_name name of the parameter. Note, it is passed through - /// but unused, parameter is currently always "Dhcp6/subnet6[X]/pool" - /// @param pools storage container in which to store the parsed pool - /// upon "commit" - Pool6Parser(const std::string& param_name, PoolStoragePtr pools) - :PoolParser(param_name, pools, AF_INET6) { + /// @param pools storage container in which to store the parsed pool. + Pool6Parser(PoolStoragePtr pools) : PoolParser(pools) { } protected: @@ -113,15 +109,26 @@ protected: } }; -class Pools6ListParser : public PoolsListParser { +/// @brief Specialization of the pool list parser for DHCPv6 +class Pools6ListParser : PoolsListParser { public: - Pools6ListParser(const std::string& dummy, PoolStoragePtr pools) - :PoolsListParser(dummy, pools) { + /// @brief Constructor. + /// + /// @param pools storage container in which to store the parsed pool. + Pools6ListParser(PoolStoragePtr pools) : PoolsListParser(pools) { } -protected: - virtual ParserPtr poolParserMaker(PoolStoragePtr storage) { - return (ParserPtr(new Pool6Parser("pool", storage))); + /// @brief parses the actual structure + /// + /// This method parses the actual list of pools. + /// + /// @param pools_list a list of pool structures + /// @throw isc::dhcp::DhcpConfigError when pool parsing fails + void parse(isc::data::ConstElementPtr pools_list) { + BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) { + Pool6Parser parser(pools_); + parser.parse(pool, AF_INET6); + } } }; @@ -142,23 +149,14 @@ protected: /// } /// @endcode /// -class PdPoolParser : public DhcpConfigParser { +class PdPoolParser : public isc::data::SimpleParser { public: /// @brief Constructor. /// - /// @param param_name name of the parameter. Note, it is passed through - /// but unused, parameter is currently always "Dhcp6/subnet6[X]/pool" - /// @param pools storage container in which to store the parsed pool - /// upon "commit" - PdPoolParser(const std::string&, PoolStoragePtr pools) - : uint32_values_(new Uint32Storage()), - string_values_(new StringStorage()), pools_(pools), - options_(new CfgOption()) { - if (!pools_) { - isc_throw(isc::dhcp::DhcpConfigError, - "PdPoolParser context storage may not be NULL"); - } + /// @param pools storage container in which to store the parsed pool. + PdPoolParser(PoolStoragePtr pools) + : pools_(pools), options_(new CfgOption()) { } /// @brief Builds a prefix delegation pool from the given configuration @@ -170,53 +168,67 @@ public: /// that define a prefix delegation pool. /// /// @throw DhcpConfigError if configuration parsing fails. - virtual void build(ConstElementPtr pd_pool_) { + void parse(ConstElementPtr pd_pool_) { + std::string addr_str; + std::string excluded_prefix_str = "::"; + int64_t prefix_len; + int64_t delegated_len; + int64_t excluded_prefix_len = 0; + bool got_prefix = false; + bool got_prefix_len = false; + bool got_delegated_len = false; + // Parse the elements that make up the option definition. BOOST_FOREACH(ConfigPair param, pd_pool_->mapValue()) { std::string entry(param.first); - ParserPtr parser; - if (entry == "prefix" || entry =="excluded-prefix") { - StringParserPtr str_parser(new StringParser(entry, - string_values_)); - parser = str_parser; - } else if (entry == "prefix-len" || entry == "delegated-len" || - entry == "excluded-prefix-len") { - Uint32ParserPtr code_parser(new Uint32Parser(entry, - uint32_values_)); - parser = code_parser; - } else if (entry == "option-data") { - OptionDataListParser opts_parser(AF_INET6); - opts_parser.parse(options_, param.second); - - // OptionDataListParser is converted to SimpleParser already, - // no need to go through build/commit phases. - continue; - } else if (entry == "user-context") { - user_context_ = param.second; - continue; // no parser to remember, simply store the value - } else { - isc_throw(DhcpConfigError, "unsupported parameter: " << entry - << " (" << param.second->getPosition() << ")"); + ConstElementPtr value(param.second); + try { + if (entry == "prefix") { + addr_str = value->stringValue(); + got_prefix = true; + } else if (entry == "excluded-prefix") { + excluded_prefix_str = value->stringValue(); + } else if (entry == "prefix-len") { + prefix_len = value->intValue(); + got_prefix_len = true; + } else if (entry == "delegated-len") { + delegated_len = value->intValue(); + got_delegated_len = true; + } else if (entry == "excluded-prefix-len") { + excluded_prefix_len = value->intValue(); + } else if (entry == "option-data") { + OptionDataListParser opts_parser(AF_INET6); + opts_parser.parse(options_, value); + } else if (entry == "user-context") { + user_context_ = value; + } else { + isc_throw(DhcpConfigError, + "unsupported parameter: " << entry + << " (" << value->getPosition() << ")"); + } + } catch (const isc::data::TypeError&) { + isc_throw(isc::dhcp::DhcpConfigError, + "invalid value type specified for parameter '" + << entry << "' (" + << value->getPosition() << ")"); } - - parser->build(param.second); - parser->commit(); } - // Try to obtain the pool parameters. It will throw an exception if any + // Check the pool parameters. It will throw an exception if any // of the required parameters are not present or invalid. + if (!got_prefix || !got_prefix_len || !got_delegated_len) { + isc_throw(isc::dhcp::DhcpConfigError, + "Missing parameter '" + << (!got_prefix ? "prefix" : + (!got_prefix_len ? "prefix-len" : "delegated-len")) + << "' (" << pd_pool_->getPosition() << ")"); + } try { - const std::string addr_str = string_values_->getParam("prefix"); - const uint32_t prefix_len = uint32_values_->getParam("prefix-len"); - const uint32_t delegated_len = uint32_values_->getParam("delegated-len"); - const std::string excluded_prefix_str = - string_values_->getOptionalParam("excluded-prefix", "::"); - const uint32_t excluded_prefix_len = - uint32_values_->getOptionalParam("excluded-prefix-len", 0); - // Attempt to construct the local pool. - pool_.reset(new Pool6(IOAddress(addr_str), prefix_len, - delegated_len, IOAddress(excluded_prefix_str), + pool_.reset(new Pool6(IOAddress(addr_str), + prefix_len, + delegated_len, + IOAddress(excluded_prefix_str), excluded_prefix_len)); // Merge options specified for a pool into pool configuration. options_->copyTo(*pool_->getCfgOption()); @@ -231,23 +243,12 @@ public: if (user_context_) { pool_->setUserContext(user_context_); } - } - // @brief Commits the constructed local pool to the pool storage. - virtual void commit() { // Add the local pool to the external storage ptr. pools_->push_back(pool_); } protected: - /// Storage for subnet-specific integer values. - Uint32StoragePtr uint32_values_; - - /// Storage for subnet-specific string values. - StringStoragePtr string_values_; - - /// Parsers are stored here. - ParserCollection parsers_; /// Pointer to the created pool object. isc::dhcp::Pool6Ptr pool_; @@ -266,21 +267,13 @@ protected: /// This parser iterates over a list of prefix delegation pool entries and /// creates pool instances for each one. If the parsing is successful, the /// collection of pools is committed to the provided storage. -class PdPoolListParser : public DhcpConfigParser { +class PdPoolListParser : public PoolsListParser { public: /// @brief Constructor. /// - /// @param dummy first argument is ignored, all Parser constructors - /// accept string as first argument. /// @param storage is the pool storage in which to store the parsed /// pools in this list - /// @throw isc::dhcp::DhcpConfigError if storage is null. - PdPoolListParser(const std::string&, PoolStoragePtr pools) - : local_pools_(new PoolStorage()), pools_(pools) { - if (!pools_) { - isc_throw(isc::dhcp::DhcpConfigError, - "PdPoolListParser pools storage may not be NULL"); - } + PdPoolListParser(PoolStoragePtr pools) : PoolsListParser(pools) { } /// @brief Parse configuration entries. @@ -292,47 +285,13 @@ public: /// that define a prefix delegation pool. /// /// @throw DhcpConfigError if configuration parsing fails. - void build(isc::data::ConstElementPtr pd_pool_list) { - // Make sure the local list is empty. - local_pools_.reset(new PoolStorage()); - - // Make sure we have a configuration elements to parse. - if (!pd_pool_list) { - isc_throw(DhcpConfigError, - "PdPoolListParser: list of pool definitions is NULL"); - } - + void parse(isc::data::ConstElementPtr pd_pool_list) { // Loop through the list of pd pools. BOOST_FOREACH(ConstElementPtr pd_pool, pd_pool_list->listValue()) { - boost::shared_ptr - // Create the PdPool parser. - parser(new PdPoolParser("pd-pool", local_pools_)); - // Build the pool instance - parser->build(pd_pool); - // Commit the pool to the local list of pools. - parser->commit(); + PdPoolParser parser(pools_); + parser.parse(pd_pool); } } - - /// @brief Commits the pools created to the external storage area. - /// - /// Note that this method adds the local list of pools to the storage area - /// rather than replacing its contents. This permits other parsers to - /// contribute to the set of pools. - void commit() { - // local_pools_ holds the values produced by the build function. - // At this point parsing should have completed successfully so - // we can append new data to the supplied storage. - pools_->insert(pools_->end(), local_pools_->begin(), - local_pools_->end()); - } - -private: - /// @brief storage for local pools - PoolStoragePtr local_pools_; - - /// @brief External storage where pools are stored upon list commit. - PoolStoragePtr pools_; }; /// @anchor Subnet6ConfigParser @@ -357,6 +316,18 @@ public: /// /// @param subnet A new subnet being configured. void build(ConstElementPtr subnet) { + /// Parse all pools first. + ConstElementPtr pools = subnet->get("pools"); + if (pools) { + Pools6ListParser parser(pools_); + parser.parse(pools); + } + ConstElementPtr pd_pools = subnet->get("pd-pools"); + if (pd_pools) { + PdPoolListParser parser(pools_); + parser.parse(pd_pools); + } + SubnetConfigParser::build(subnet); if (subnet_) { @@ -421,11 +392,9 @@ protected: (config_id.compare("interface-id") == 0) || (config_id.compare("reservation-mode") == 0)) { parser = new StringParser(config_id, string_values_); - } else if (config_id.compare("pools") == 0) { - parser = new Pools6ListParser(config_id, pools_); + // pools has been converted to SimpleParser. // relay has been converted to SimpleParser. - } else if (config_id.compare("pd-pools") == 0) { - parser = new PdPoolListParser(config_id, pools_); + // pd-pools has been converted to SimpleParser. // option-data was here, but it is now converted to SimpleParser } else if (config_id.compare("rapid-commit") == 0) { parser = new BooleanParser(config_id, boolean_values_); diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index cf3e116b76..265ad21989 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -852,60 +852,16 @@ RelayInfoParser::parse(const isc::dhcp::Subnet::RelayInfoPtr& cfg, *cfg = isc::dhcp::Subnet::RelayInfo(ip); } -//****************************** PoolsListParser ******************************** -PoolsListParser::PoolsListParser(const std::string&, PoolStoragePtr pools) - :pools_(pools), local_pools_(new PoolStorage()) { - if (!pools_) { - isc_throw(isc::dhcp::DhcpConfigError, "parser logic error: " - << "storage may not be NULL"); - } -} - -void -PoolsListParser::build(ConstElementPtr pools) { - BOOST_FOREACH(ConstElementPtr pool, pools->listValue()) { - - // Iterate over every structure on the pools list and invoke - // a separate parser for it. - ParserPtr parser = poolParserMaker(local_pools_); - - parser->build(pool); - - // Let's store the parser, but do not commit anything yet - parsers_.push_back(parser); - } -} - -void PoolsListParser::commit() { - - // Commit each parser first. It will store the pool structure - // in pools_. - BOOST_FOREACH(ParserPtr parser, parsers_) { - parser->commit(); - } - - if (pools_) { - // local_pools_ holds the values produced by the build function. - // At this point parsing should have completed successfuly so - // we can append new data to the supplied storage. - pools_->insert(pools_->end(), local_pools_->begin(), local_pools_->end()); - } -} - //****************************** PoolParser ******************************** -PoolParser::PoolParser(const std::string&, PoolStoragePtr pools, - const uint16_t address_family) - :pools_(pools), options_(new CfgOption()), - address_family_(address_family) { +PoolParser::PoolParser(PoolStoragePtr pools) : pools_(pools) { +} - if (!pools_) { - isc_throw(isc::dhcp::DhcpConfigError, "parser logic error: " - << "storage may not be NULL"); - } +PoolParser::~PoolParser() { } void -PoolParser::build(ConstElementPtr pool_structure) { +PoolParser::parse(ConstElementPtr pool_structure, + const uint16_t address_family) { ConstElementPtr text_pool = pool_structure->get("pool"); @@ -952,7 +908,7 @@ PoolParser::build(ConstElementPtr pool_structure) { } pool = poolMaker(addr, len); - local_pools_.push_back(pool); + pools_->push_back(pool); // If there's user-context specified, store it. ConstElementPtr user_context = pool_structure->get("user-context"); @@ -974,7 +930,7 @@ PoolParser::build(ConstElementPtr pool_structure) { isc::asiolink::IOAddress max(txt.substr(pos + 1)); pool = poolMaker(min, max); - local_pools_.push_back(pool); + pools_->push_back(pool); } } @@ -991,13 +947,13 @@ PoolParser::build(ConstElementPtr pool_structure) { if (option_data) { try { // Currently we don't support specifying options for the DHCPv4 server. - if (address_family_ == AF_INET) { + if (address_family == AF_INET) { isc_throw(DhcpConfigError, "option-data is not supported for DHCPv4" " address pools"); } CfgOptionPtr cfg = pool->getCfgOption(); - OptionDataListParser option_parser(address_family_); + OptionDataListParser option_parser(address_family); option_parser.parse(cfg, option_data); } catch (const std::exception& ex) { isc_throw(isc::dhcp::DhcpConfigError, ex.what() @@ -1006,16 +962,6 @@ PoolParser::build(ConstElementPtr pool_structure) { } } -void -PoolParser::commit() { - if (pools_) { - // local_pools_ holds the values produced by the build function. - // At this point parsing should have completed successfuly so - // we can append new data to the supplied storage. - pools_->insert(pools_->end(), local_pools_.begin(), local_pools_.end()); - } -} - //****************************** SubnetConfigParser ************************* SubnetConfigParser::SubnetConfigParser(const std::string&, @@ -1040,6 +986,17 @@ SubnetConfigParser::SubnetConfigParser(const std::string&, void SubnetConfigParser::build(ConstElementPtr subnet) { BOOST_FOREACH(ConfigPair param, subnet->mapValue()) { + // Pools has been converted to SimpleParser. + if (param.first == "pools") { + continue; + } + + // PdPools has been converted to SimpleParser. + if ((param.first == "pd-pools") && + (global_context_->universe_ == Option::V6)) { + continue; + } + // Host reservations must be parsed after subnet specific parameters. // Note that the reservation parsing will be invoked by the build() // in the derived classes, i.e. Subnet4ConfigParser and diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.h b/src/lib/dhcpsrv/parsers/dhcp_parsers.h index dcd7528acd..2cfe6e625e 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.h +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.h @@ -703,19 +703,16 @@ typedef boost::shared_ptr PoolStoragePtr; /// and stored in chosen PoolStorage container. /// /// It is useful for parsing Dhcp<4/6>/subnet<4/6>[X]/pools[X] structure. -class PoolParser : public DhcpConfigParser { +class PoolParser : public isc::data::SimpleParser { public: /// @brief constructor. /// - /// @param dummy first argument is ignored, all Parser constructors - /// accept string as first argument. /// @param pools is the storage in which to store the parsed pool - /// upon "commit". - /// @param address_family AF_INET (for DHCPv4) or AF_INET6 (for DHCPv6). - /// @throw isc::dhcp::DhcpConfigError if storage is null. - PoolParser(const std::string& dummy, PoolStoragePtr pools, - const uint16_t address_family); + PoolParser(PoolStoragePtr pools); + + /// @brief destructor. + virtual ~PoolParser(); /// @brief parses the actual structure /// @@ -723,12 +720,10 @@ public: /// No validation is done at this stage, everything is interpreted as /// interface name. /// @param pool_structure a single entry on a list of pools + /// @param address_family AF_INET (for DHCPv4) or AF_INET6 (for DHCPv6). /// @throw isc::dhcp::DhcpConfigError when pool parsing fails - virtual void build(isc::data::ConstElementPtr pool_structure); - - /// @brief Stores the parsed values in a storage provided - /// by an upper level parser. - virtual void commit(); + virtual void parse(isc::data::ConstElementPtr pool_structure, + const uint16_t address_family); protected: /// @brief Creates a Pool object given a IPv4 prefix and the prefix length. @@ -738,7 +733,7 @@ protected: /// @param ptype is the type of pool to create. /// @return returns a PoolPtr to the new Pool object. virtual PoolPtr poolMaker(isc::asiolink::IOAddress &addr, uint32_t len, - int32_t ptype=0) = 0; + int32_t ptype = 0) = 0; /// @brief Creates a Pool object given starting and ending IP addresses. /// @@ -747,23 +742,14 @@ protected: /// @param ptype is the type of pool to create (not used by all derivations) /// @return returns a PoolPtr to the new Pool object. virtual PoolPtr poolMaker(isc::asiolink::IOAddress &min, - isc::asiolink::IOAddress &max, int32_t ptype=0) = 0; + isc::asiolink::IOAddress &max, + int32_t ptype = 0) = 0; /// @brief pointer to the actual Pools storage /// /// That is typically a storage somewhere in Subnet parser /// (an upper level parser). PoolStoragePtr pools_; - - /// A temporary storage for pools configuration. It is a - /// storage where pools are stored by build function. - PoolStorage local_pools_; - - /// A storage for pool specific option values. - CfgOptionPtr options_; - - /// @brief Address family: AF_INET (for DHCPv4) or AF_INET6 for DHCPv6. - uint16_t address_family_; }; /// @brief Parser for a list of pools @@ -771,54 +757,34 @@ protected: /// This parser parses a list pools. Each element on that list gets its own /// parser, created with poolParserMaker() method. That method must be specified /// for each protocol family (v4 or v6) separately. -/// -/// This class is not intended to be used directly. Instead, derived classes -/// should implement poolParserMaker() method. -class PoolsListParser : public DhcpConfigParser { +class PoolsListParser : public isc::data::SimpleParser { public: /// @brief constructor. /// - /// @param dummy first argument is ignored, all Parser constructors - /// accept a string as the first argument. - /// @param pools is the storage in which to store the parsed pool - /// upon "commit". - /// @throw isc::dhcp::DhcpConfigError if storage is null. - PoolsListParser(const std::string& dummy, PoolStoragePtr pools); + /// @param pools is the storage in which to store the parsed pools. + PoolsListParser(PoolStoragePtr pools) : pools_(pools) { + } + + /// @brief destructor. + virtual ~PoolsListParser() { + } /// @brief parses the actual structure /// - /// This method parses the actual list of pools. It creates a parser - /// for each structure using poolParserMaker(). + /// This method parses the actual list of pools. /// /// @param pools_list a list of pool structures /// @throw isc::dhcp::DhcpConfigError when pool parsing fails - virtual void build(isc::data::ConstElementPtr pools_list); - - /// @brief Stores the parsed values in storage provided - /// by an upper level parser. - virtual void commit(); + virtual void parse(isc::data::ConstElementPtr pools_list) = 0; protected: - /// @brief Creates a PoolParser object - /// - /// Instantiates appropriate (v4 or v6) PoolParser object. - /// @param storage parameter that is passed to ParserMaker() constructor. - virtual ParserPtr poolParserMaker(PoolStoragePtr storage) = 0; - /// @brief pointer to the actual Pools storage /// /// That is typically a storage somewhere in Subnet parser /// (an upper level parser). PoolStoragePtr pools_; - - /// A temporary storage for pools configuration. It is the - /// storage where pools are stored by the build function. - PoolStoragePtr local_pools_; - - /// Collection of parsers; - ParserCollection parsers_; }; /// @brief parser for additional relay information -- 2.47.3