diff --git a/doc/sphinx/arm/config-backend.rst b/doc/sphinx/arm/config-backend.rst index ed6ee93d9873eca9fb61a13ebc2a1fdfb758d4ec..9535c0c78665b5445b1d2308eeeeedb356d54415 100644 --- a/doc/sphinx/arm/config-backend.rst +++ b/doc/sphinx/arm/config-backend.rst @@ -138,6 +138,26 @@ The current CB limitations will be gradually removed in subsequent Kea releases. not in the database. Use the ``cb_cmds`` hooks library to manage the subnets information in the database instead. +.. note:: + + Using custom option formats requires creating definitions for these options. + Suppose a user wishes to set option data in the configuration backend. In + that case, we recommend specifying the definition for that option in the + configuration backend as well. It is essential when multiple servers are + managed via the configuration backend, and may differ in their + configurations. The option data parser can search for an option definition + appropriate for the server for which the option data is specified. + + In a single-server deployment, or when all servers share the same + configuration file information, it is possible to specify option + definitions in the configuration files and option data in the configuration + backend. The server receiving a command to set option data must have a + valid definition in its configuration file, even when it sets option data + for another server. + + It is not supported to specify option definitions in the configuration + backend and the corresponding option data in the server configuration files. + CB Components ------------- diff --git a/doc/sphinx/arm/hooks-cb-cmds.rst b/doc/sphinx/arm/hooks-cb-cmds.rst index 5f4547980aff29281476f3b94ad0f56686e40342..ba414ab5eff08e62e9a7307c9efd3a45866de5e9 100644 --- a/doc/sphinx/arm/hooks-cb-cmds.rst +++ b/doc/sphinx/arm/hooks-cb-cmds.rst @@ -21,6 +21,11 @@ support contract. This library may only be loaded by the ``kea-dhcp4`` or ``kea-dhcp6`` process. +.. note:: + + Please read about :ref:`cb-limitations` before using the commands + described in this section. + Commands Structure ~~~~~~~~~~~~~~~~~~ @@ -1014,7 +1019,7 @@ These commands create a new DHCP option definition or replace an existing option definition in the database. The structure of the option definition information is the same as in the Kea configuration file (see :ref:`dhcp4-custom-options` and :ref:`dhcp6-custom-options`). -The following command creates the DHCPv4 option definition in the +The following command creates the DHCPv4 option definition at the top-level "dhcp4" option space and associates it with the "server1": .. code-block:: json @@ -1042,7 +1047,8 @@ top-level "dhcp4" option space and associates it with the "server1": The `server-tags` list must include exactly one server tag or the keyword "all". It must not contain the -`null` value. +`null` value. + .. _command-remote-option4-global-del: diff --git a/src/lib/dhcpsrv/parsers/client_class_def_parser.cc b/src/lib/dhcpsrv/parsers/client_class_def_parser.cc index 348694195ad9247eef13c86507d663b99f796625..4899f0a79f5257e09af27e821f952cbc4a76b65e 100644 --- a/src/lib/dhcpsrv/parsers/client_class_def_parser.cc +++ b/src/lib/dhcpsrv/parsers/client_class_def_parser.cc @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -136,8 +135,8 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary, CfgOptionPtr options(new CfgOption()); ConstElementPtr option_data = class_def_cfg->get("option-data"); if (option_data) { - OptionDataListParser opts_parser(family, defs); - opts_parser.parse(options, option_data); + auto opts_parser = createOptionDataListParser(family, defs); + opts_parser->parse(options, option_data); } // Parse user context @@ -294,6 +293,12 @@ ClientClassDefParser::checkParametersSupported(const ConstElementPtr& class_def_ } } +boost::shared_ptr +ClientClassDefParser::createOptionDataListParser(const uint16_t address_family, + CfgOptionDefPtr cfg_option_def) const { + auto parser = boost::make_shared(address_family, cfg_option_def); + return (parser); +} // ****************** ClientClassDefListParser ************************ diff --git a/src/lib/dhcpsrv/parsers/client_class_def_parser.h b/src/lib/dhcpsrv/parsers/client_class_def_parser.h index 8350ba73e41723f97b89ff393897081dfc95c1fd..060ab10abcc1443983d9aff7b53f1ff3b066cc61 100644 --- a/src/lib/dhcpsrv/parsers/client_class_def_parser.h +++ b/src/lib/dhcpsrv/parsers/client_class_def_parser.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -83,6 +84,10 @@ public: class ClientClassDefParser : public isc::data::SimpleParser { public: + /// @brief Virtual destructor. + virtual ~ClientClassDefParser() { + } + /// @brief Parses an entry that describes single client class definition. /// /// Attempts to add the new class directly into the given dictionary. @@ -115,6 +120,22 @@ public: /// @throw DhcpConfigError if any of the parameters is not supported. void checkParametersSupported(const isc::data::ConstElementPtr& class_def_cfg, const uint16_t family); + +protected: + + /// @brief Returns an instance of the @c OptionDataListParser to + /// be used in parsing the option-data structure. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for option data. + /// + /// @param address_family @c AF_INET (for DHCPv4) or @c AF_INET6 (for DHCPv6). + /// @param cfg_option_def structure holding option definitions. + /// + /// @return an instance of the @c OptionDataListParser. + virtual boost::shared_ptr + createOptionDataListParser(const uint16_t address_family, + CfgOptionDefPtr cfg_option_def) const; }; /// @brief Defines a pointer to a ClientClassDefParser diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index 5e0bcc8a45225fab78d382b21acd8203019fdd7f..46c4e2eeb4a01723a30bb1e0ebbcbaade5971f1e 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -87,32 +88,6 @@ void ControlSocketParser::parse(SrvConfig& srv_cfg, isc::data::ConstElementPtr v srv_cfg.setControlSocketInfo(value); } -template -OptionDefinitionPtr -OptionDataParser::findOptionDefinition(const std::string& option_space, - const SearchKey& search_key) const { - OptionDefinitionPtr def = LibDHCP::getOptionDef(option_space, search_key); - - if (!def) { - // Check if this is a vendor-option. If it is, get vendor-specific - // definition. - uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(option_space); - if (vendor_id) { - const Option::Universe u = address_family_ == AF_INET ? - Option::V4 : Option::V6; - def = LibDHCP::getVendorOptionDef(u, vendor_id, search_key); - } - } - - if (!def) { - // Check if this is an option specified by a user. - def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef() - ->get(option_space, search_key); - } - - return (def); -} - // ******************************** OptionDefParser **************************** OptionDefParser::OptionDefParser(const uint16_t address_family) @@ -494,8 +469,8 @@ PoolParser::parse(PoolStoragePtr pools, if (option_data) { try { CfgOptionPtr cfg = pool->getCfgOption(); - OptionDataListParser option_parser(address_family); - option_parser.parse(cfg, option_data); + auto option_parser = createOptionDataListParser(address_family); + option_parser->parse(cfg, option_data); } catch (const std::exception& ex) { isc_throw(isc::dhcp::DhcpConfigError, ex.what() << " (" << option_data->getPosition() << ")"); @@ -527,6 +502,12 @@ PoolParser::parse(PoolStoragePtr pools, } } +boost::shared_ptr +PoolParser::createOptionDataListParser(const uint16_t address_family) const { + auto parser = boost::make_shared(address_family); + return (parser); +} + //****************************** Pool4Parser ************************* PoolPtr @@ -539,16 +520,22 @@ Pool4Parser::poolMaker (IOAddress &min, IOAddress &max, int32_t) { return (PoolPtr(new Pool4(min, max))); } -//****************************** Pool4ListParser ************************* +//****************************** Pools4ListParser ************************* void Pools4ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list) { BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) { - Pool4Parser parser; - parser.parse(pools, pool, AF_INET); + auto parser = createPoolConfigParser(); + parser->parse(pools, pool, AF_INET); } } +boost::shared_ptr +Pools4ListParser::createPoolConfigParser() const { + auto parser = boost::make_shared(); + return (parser); +} + //****************************** SubnetConfigParser ************************* SubnetConfigParser::SubnetConfigParser(uint16_t family, bool check_iface) @@ -564,8 +551,8 @@ SubnetConfigParser::parse(ConstElementPtr subnet) { ConstElementPtr options_params = subnet->get("option-data"); if (options_params) { - OptionDataListParser opt_parser(address_family_); - opt_parser.parse(options_, options_params); + auto opt_parser = createOptionDataListParser(); + opt_parser->parse(options_, options_params); } ConstElementPtr relay_params = subnet->get("relay"); @@ -627,7 +614,7 @@ SubnetConfigParser::createSubnet(ConstElementPtr params) { ConstElementPtr elem = params->get("subnet"); isc_throw(DhcpConfigError, "prefix length: '" << subnet_txt.substr(pos+1) << "' is not an integer (" - << elem->getPosition() << ")"); + << elem->getPosition() << ")"); } // Sanity check the prefix length @@ -671,7 +658,12 @@ SubnetConfigParser::createSubnet(ConstElementPtr params) { subnet_->setFetchGlobalsFn([]() -> ConstElementPtr { return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals()); }); +} +boost::shared_ptr +SubnetConfigParser::createOptionDataListParser() const { + auto parser = boost::make_shared(address_family_); + return (parser); } //****************************** Subnet4ConfigParser ************************* @@ -688,8 +680,8 @@ Subnet4ConfigParser::parse(ConstElementPtr subnet) { /// Parse Pools first. ConstElementPtr pools = subnet->get("pools"); if (pools) { - Pools4ListParser parser; - parser.parse(pools_, pools); + auto parser = createPoolsListParser(); + parser->parse(pools_, pools); } SubnetPtr generic = SubnetConfigParser::parse(subnet); @@ -960,6 +952,12 @@ Subnet4ConfigParser::validateResv(const Subnet4Ptr& subnet, ConstHostPtr host) { } } +boost::shared_ptr +Subnet4ConfigParser::createPoolsListParser() const { + auto parser = boost::make_shared(); + return (parser); +} + //**************************** Subnets4ListConfigParser ********************** Subnets4ListConfigParser::Subnets4ListConfigParser(bool check_iface) @@ -972,8 +970,8 @@ Subnets4ListConfigParser::parse(SrvConfigPtr cfg, size_t cnt = 0; BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) { - Subnet4ConfigParser parser(check_iface_); - Subnet4Ptr subnet = parser.parse(subnet_json); + auto parser = createSubnetConfigParser(); + Subnet4Ptr subnet = parser->parse(subnet_json); if (subnet) { // Adding a subnet to the Configuration Manager may fail if the @@ -997,8 +995,8 @@ Subnets4ListConfigParser::parse(Subnet4Collection& subnets, size_t cnt = 0; BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) { - Subnet4ConfigParser parser(check_iface_); - Subnet4Ptr subnet = parser.parse(subnet_json); + auto parser = createSubnetConfigParser(); + Subnet4Ptr subnet = parser->parse(subnet_json); if (subnet) { try { auto ret = subnets.insert(subnet); @@ -1016,6 +1014,11 @@ Subnets4ListConfigParser::parse(Subnet4Collection& subnets, return (cnt); } +boost::shared_ptr +Subnets4ListConfigParser::createSubnetConfigParser() const { + auto parser = boost::make_shared(check_iface_); + return (parser); +} //**************************** Pool6Parser ********************************* @@ -1039,11 +1042,17 @@ Pool6Parser::poolMaker (IOAddress &min, IOAddress &max, int32_t ptype) void Pools6ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list) { BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) { - Pool6Parser parser; - parser.parse(pools, pool, AF_INET6); + auto parser = createPoolConfigParser(); + parser->parse(pools, pool, AF_INET6); } } +boost::shared_ptr +Pools6ListParser::createPoolConfigParser() const { + auto parser = boost::make_shared(); + return (parser); +} + //**************************** PdPoolParser ****************************** PdPoolParser::PdPoolParser() : options_(new CfgOption()) { @@ -1071,8 +1080,8 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) { ConstElementPtr option_data = pd_pool_->get("option-data"); if (option_data) { - OptionDataListParser opts_parser(AF_INET6); - opts_parser.parse(options_, option_data); + auto opts_parser = createOptionDataListParser(); + opts_parser->parse(options_, option_data); } ConstElementPtr user_context = pd_pool_->get("user-context"); @@ -1134,17 +1143,29 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) { pools->push_back(pool_); } +boost::shared_ptr +PdPoolParser::createOptionDataListParser() const { + auto parser = boost::make_shared(AF_INET6); + return (parser); +} + //**************************** PdPoolsListParser ************************ void PdPoolsListParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_list) { // Loop through the list of pd pools. BOOST_FOREACH(ConstElementPtr pd_pool, pd_pool_list->listValue()) { - PdPoolParser parser; - parser.parse(pools, pd_pool); + auto parser = createPdPoolConfigParser(); + parser->parse(pools, pd_pool); } } +boost::shared_ptr +PdPoolsListParser::createPdPoolConfigParser() const { + auto parser = boost::make_shared(); + return (parser); +} + //**************************** Subnet6ConfigParser *********************** Subnet6ConfigParser::Subnet6ConfigParser(bool check_iface) @@ -1159,13 +1180,13 @@ Subnet6ConfigParser::parse(ConstElementPtr subnet) { /// Parse all pools first. ConstElementPtr pools = subnet->get("pools"); if (pools) { - Pools6ListParser parser; - parser.parse(pools_, pools); + auto parser = createPoolsListParser(); + parser->parse(pools_, pools); } ConstElementPtr pd_pools = subnet->get("pd-pools"); if (pd_pools) { - PdPoolsListParser parser; - parser.parse(pools_, pd_pools); + auto parser = createPdPoolsListParser(); + parser->parse(pools_, pd_pools); } SubnetPtr generic = SubnetConfigParser::parse(subnet); @@ -1391,6 +1412,18 @@ Subnet6ConfigParser::validateResvs(const Subnet6Ptr& subnet, ConstHostPtr host) } } +boost::shared_ptr +Subnet6ConfigParser::createPoolsListParser() const { + auto parser = boost::make_shared(); + return (parser); +} + +boost::shared_ptr +Subnet6ConfigParser::createPdPoolsListParser() const { + auto parser = boost::make_shared(); + return (parser); +} + //**************************** Subnet6ListConfigParser ******************** Subnets6ListConfigParser::Subnets6ListConfigParser(bool check_iface) @@ -1403,8 +1436,8 @@ Subnets6ListConfigParser::parse(SrvConfigPtr cfg, size_t cnt = 0; BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) { - Subnet6ConfigParser parser(check_iface_); - Subnet6Ptr subnet = parser.parse(subnet_json); + auto parser = createSubnetConfigParser(); + Subnet6Ptr subnet = parser->parse(subnet_json); // Adding a subnet to the Configuration Manager may fail if the // subnet id is invalid (duplicate). Thus, we catch exceptions @@ -1426,8 +1459,8 @@ Subnets6ListConfigParser::parse(Subnet6Collection& subnets, size_t cnt = 0; BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) { - Subnet6ConfigParser parser(check_iface_); - Subnet6Ptr subnet = parser.parse(subnet_json); + auto parser = createSubnetConfigParser(); + Subnet6Ptr subnet = parser->parse(subnet_json); if (subnet) { try { auto ret = subnets.insert(subnet); @@ -1445,6 +1478,11 @@ Subnets6ListConfigParser::parse(Subnet6Collection& subnets, return (cnt); } +boost::shared_ptr +Subnets6ListConfigParser::createSubnetConfigParser() const { + auto parser = boost::make_shared(check_iface_); + return (parser); +} //**************************** D2ClientConfigParser ********************** diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.h b/src/lib/dhcpsrv/parsers/dhcp_parsers.h index ba040773a37fa3c17b4e88af0b00ba1b74a0253a..b5c5053e2bd735a8f741864d043a81e4aeafe81e 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.h +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -325,6 +326,18 @@ protected: virtual PoolPtr poolMaker(isc::asiolink::IOAddress &min, isc::asiolink::IOAddress &max, int32_t ptype = 0) = 0; + + /// @brief Returns an instance of the @c OptionDataListParser to + /// be used in parsing the option-data structure. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for option data. + /// + /// @param address_family AF_INET (for DHCPv4) or AF_INET6 (for DHCPv6). + /// + /// @return an instance of the @c OptionDataListParser. + virtual boost::shared_ptr + createOptionDataListParser(const uint16_t address_family) const; }; /// @brief Parser for IPv4 pool definitions. @@ -379,10 +392,21 @@ public: /// @throw isc::dhcp::DhcpConfigError when pool parsing fails virtual void parse(PoolStoragePtr pools, isc::data::ConstElementPtr pools_list) = 0; + +protected: + + /// @brief Returns an instance of the @c PoolParser to be used in + /// parsing the address pools. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the pools. + /// + /// @return an instance of the @c PoolParser. + virtual boost::shared_ptr createPoolConfigParser() const = 0; }; /// @brief Specialization of the pool list parser for DHCPv4 -class Pools4ListParser : PoolsListParser { +class Pools4ListParser : public PoolsListParser { public: /// @brief parses the actual structure @@ -393,6 +417,17 @@ public: /// @param pools_list a list of pool structures /// @throw isc::dhcp::DhcpConfigError when pool parsing fails void parse(PoolStoragePtr pools, data::ConstElementPtr pools_list); + +protected: + + /// @brief Returns an instance of the @c Pool4Parser to be used in + /// parsing the address pools. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the pools. + /// + /// @return an instance of the @c Pool4Parser. + virtual boost::shared_ptr createPoolConfigParser() const; }; /// @brief parser for additional relay information @@ -499,7 +534,7 @@ protected: virtual void initSubnet(isc::data::ConstElementPtr params, isc::asiolink::IOAddress addr, uint8_t len) = 0; -private: +protected: /// @brief Create a new subnet using a data from child parsers. /// @@ -508,7 +543,24 @@ private: /// failed. void createSubnet(isc::data::ConstElementPtr data); -protected: + /// @brief Returns an instance of the @c OptionDataListParser to + /// be used in parsing the option-data structure. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for option data. + /// + /// @return an instance of the @c OptionDataListParser. + virtual boost::shared_ptr createOptionDataListParser() const; + + /// @brief Returns an instance of the @c PoolsListParser to be used + /// in parsing the address pools. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the pools. + /// + /// @return an instance of the @c PoolsListParser. + virtual boost::shared_ptr + createPoolsListParser() const = 0; /// Storage for pools belonging to this subnet. PoolStoragePtr pools_; @@ -569,6 +621,16 @@ protected: /// @param host pointer to the host reservation /// @throw DhcpConfigError when the address is not in the subnet range. void validateResv(const Subnet4Ptr& subnet, ConstHostPtr host); + + /// @brief Returns an instance of the @c Pools4ListParser to be used + /// in parsing the address pools. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the pools. + /// + /// @return an instance of the @c Pools4ListParser. + virtual boost::shared_ptr + createPoolsListParser() const; }; /// @brief this class parses list of DHCP4 subnets @@ -585,6 +647,10 @@ public: /// the system. Subnets4ListConfigParser(bool check_iface = true); + /// @brief Virtual destructor. + virtual ~Subnets4ListConfigParser() { + } + /// @brief parses contents of the list /// /// Iterates over all entries on the list, parses its content @@ -606,6 +672,15 @@ public: protected: + /// @brief Returns an instance of the @c Subnet4ConfigParser to be + /// used in parsing the subnets. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the subnets. + /// + /// @return an instance of the @c Subnet4ConfigParser. + virtual boost::shared_ptr createSubnetConfigParser() const; + /// Check if the specified interface exists in the system. bool check_iface_; }; @@ -643,7 +718,7 @@ protected: }; /// @brief Specialization of the pool list parser for DHCPv6 -class Pools6ListParser : PoolsListParser { +class Pools6ListParser : public PoolsListParser { public: /// @brief parses the actual structure @@ -654,6 +729,17 @@ public: /// @param pools_list a list of pool structures /// @throw isc::dhcp::DhcpConfigError when pool parsing fails void parse(PoolStoragePtr pools, data::ConstElementPtr pools_list); + +protected: + + /// @brief Returns an instance of the @c Pool6Parser to be used in + /// parsing the address pools. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the pools. + /// + /// @return an instance of the @c Pool6Parser. + virtual boost::shared_ptr createPoolConfigParser() const; }; /// @brief Parser for IPv6 prefix delegation definitions. @@ -680,6 +766,10 @@ public: /// PdPoolParser(); + /// @brief Virtual destructor. + virtual ~PdPoolParser() { + } + /// @brief Builds a prefix delegation pool from the given configuration /// /// This function parses configuration entries and creates an instance @@ -692,7 +782,17 @@ public: /// @throw DhcpConfigError if configuration parsing fails. void parse(PoolStoragePtr pools, data::ConstElementPtr pd_pool_); -private: +protected: + + /// @brief Returns an instance of the @c OptionDataListParser to + /// be used in parsing the option-data structure. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for option data. + /// + /// @return an instance of the @c OptionDataListParser. + virtual boost::shared_ptr + createOptionDataListParser() const; /// Pointer to the created pool object. isc::dhcp::Pool6Ptr pool_; @@ -716,9 +816,13 @@ private: /// 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 PdPoolsListParser : public PoolsListParser { +class PdPoolsListParser : public isc::data::SimpleParser { public: + /// @brief Virtual destructor. + virtual ~PdPoolsListParser() { + } + /// @brief Parse configuration entries. /// /// This function parses configuration entries and creates instances @@ -730,6 +834,18 @@ public: /// /// @throw DhcpConfigError if configuration parsing fails. void parse(PoolStoragePtr pools, data::ConstElementPtr pd_pool_list); + +protected: + + /// @brief Returns an instance of the @c PdPoolParser to be used in + /// parsing the prefix delegation pools. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the pools. + /// + /// @return an instance of the @c PdPool6Parser. + virtual boost::shared_ptr + createPdPoolConfigParser() const; }; /// @anchor Subnet6ConfigParser @@ -782,6 +898,26 @@ protected: /// @param host pointer to the host reservation /// @throw DhcpConfigError when an address is not in the subnet range. void validateResvs(const Subnet6Ptr& subnet, ConstHostPtr host); + + /// @brief Returns an instance of the @c Pools6ListParser to be used + /// in parsing the address pools. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the pools. + /// + /// @return an instance of the @c Pools6ListParser. + virtual boost::shared_ptr + createPoolsListParser() const; + + /// @brief Returns an instance of the @c PdPools6ListParser to be used + /// in parsing the prefix delegation pools. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the pools. + /// + /// @return an instance of the @c PdPools6ListParser. + virtual boost::shared_ptr + createPdPoolsListParser() const; }; @@ -799,6 +935,10 @@ public: /// the system. Subnets6ListConfigParser(bool check_iface = true); + /// @brief Virtual destructor. + virtual ~Subnets6ListConfigParser() { + } + /// @brief parses contents of the list /// /// Iterates over all entries on the list, parses its content @@ -820,6 +960,15 @@ public: protected: + /// @brief Returns an instance of the @c Subnet6ConfigParser to be + /// used in parsing the subnets. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the subnets. + /// + /// @return an instance of the @c Subnet6ConfigParser. + virtual boost::shared_ptr createSubnetConfigParser() const; + /// Check if the specified interface exists in the system. bool check_iface_; }; diff --git a/src/lib/dhcpsrv/parsers/option_data_parser.cc b/src/lib/dhcpsrv/parsers/option_data_parser.cc index 80808ffdbedb37da490f66632259c7657e4551f6..5b45ce1e6209659163a2e0fb8ad4f52ee8c4222e 100644 --- a/src/lib/dhcpsrv/parsers/option_data_parser.cc +++ b/src/lib/dhcpsrv/parsers/option_data_parser.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2017-2020 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2017-2021 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -185,19 +186,27 @@ OptionDataParser::extractPersistent(ConstElementPtr parent) const { return (Optional(persist)); } -template OptionDefinitionPtr OptionDataParser::findOptionDefinition(const std::string& option_space, - const SearchKey& search_key) const { + const Optional& option_code, + const Optional& option_name) const { OptionDefinitionPtr def; if (cfg_option_def_) { // Check if the definition was given in the constructor - def = cfg_option_def_->get(option_space, search_key); + if (option_code.unspecified()) { + def = cfg_option_def_->get(option_space, option_name); + } else { + def = cfg_option_def_->get(option_space, option_code); + } } if (!def) { // Check if this is a standard option. - def = LibDHCP::getOptionDef(option_space, search_key); + if (option_code.unspecified()) { + def = LibDHCP::getOptionDef(option_space, option_name); + } else { + def = LibDHCP::getOptionDef(option_space, option_code); + } } if (!def) { @@ -207,7 +216,11 @@ OptionDataParser::findOptionDefinition(const std::string& option_space, if (vendor_id) { const Option::Universe u = address_family_ == AF_INET ? Option::V4 : Option::V6; - def = LibDHCP::getVendorOptionDef(u, vendor_id, search_key); + if (option_code.unspecified()) { + def = LibDHCP::getVendorOptionDef(u, vendor_id, option_name); + } else { + def = LibDHCP::getVendorOptionDef(u, vendor_id, option_code); + } } } @@ -221,12 +234,20 @@ OptionDataParser::findOptionDefinition(const std::string& option_space, // the definitions from the current configuration in case there is // no staging configuration (after configuration commit). In other // words, runtime options are always the ones that we need here. - def = LibDHCP::getRuntimeOptionDef(option_space, search_key); + if (option_code.unspecified()) { + def = LibDHCP::getRuntimeOptionDef(option_space, option_name); + } else { + def = LibDHCP::getRuntimeOptionDef(option_space, option_code); + } } if (!def) { // Finish by last resort definitions. - def = LibDHCP::getLastResortOptionDef(option_space, search_key); + if (option_code.unspecified()) { + def = LibDHCP::getLastResortOptionDef(option_space, option_name); + } else { + def = LibDHCP::getLastResortOptionDef(option_space, option_code); + } } return (def); @@ -254,9 +275,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) { // Try to find a corresponding option definition using option code or // option name. - OptionDefinitionPtr def = code_param.unspecified() ? - findOptionDefinition(space_param, name_param) : - findOptionDefinition(space_param, code_param); + OptionDefinitionPtr def = findOptionDefinition(space_param, code_param, name_param); // If there is no definition, the user must not explicitly enable the // use of csv-format. @@ -407,15 +426,21 @@ OptionDataListParser::OptionDataListParser(//const std::string&, void OptionDataListParser::parse(const CfgOptionPtr& cfg, isc::data::ConstElementPtr option_data_list) { - OptionDataParser option_parser(address_family_, cfg_option_def_); + auto option_parser = createOptionDataParser(); BOOST_FOREACH(ConstElementPtr data, option_data_list->listValue()) { std::pair option = - option_parser.parse(data); + option_parser->parse(data); // Use the option description to keep the formatted value cfg->add(option.first, option.second); cfg->encapsulate(); } } +boost::shared_ptr +OptionDataListParser::createOptionDataParser() const { + auto parser = boost::make_shared(address_family_, cfg_option_def_); + return (parser); +} + } // end of namespace isc::dhcp } // end of namespace isc diff --git a/src/lib/dhcpsrv/parsers/option_data_parser.h b/src/lib/dhcpsrv/parsers/option_data_parser.h index 4d576483d89da918d2ec1837b942b17db1feba8c..a0e0c507582a13811f5a9b1972877a80324bbf3b 100644 --- a/src/lib/dhcpsrv/parsers/option_data_parser.h +++ b/src/lib/dhcpsrv/parsers/option_data_parser.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,10 @@ public: OptionDataParser(const uint16_t address_family, CfgOptionDefPtr cfg_option_def = CfgOptionDefPtr()); + /// @brief Virtual destructor. + virtual ~OptionDataParser() { + } + /// @brief Parses ElementPtr containing option definition /// /// This method parses ElementPtr containing the option definition, @@ -65,7 +70,7 @@ public: std::pair parse(isc::data::ConstElementPtr single_option); -private: +protected: /// @brief Finds an option definition within an option space /// @@ -73,18 +78,19 @@ private: /// option definition within the option definition storage. /// /// @param option_space name of the parameter option space - /// @param search_key an option code or name to be used to lookup the - /// option definition. - /// @tparam A numeric type for searching using an option code or the - /// string for searching using the option name. + /// @param option_code option code to be used to find the option + /// definition, if the option name is unspecified. + /// @param option_name option name to be used to lookup the option + /// definition. /// /// @return OptionDefinitionPtr of the option definition or an /// empty OptionDefinitionPtr if not found. /// @throw DhcpConfigError if the option space requested is not valid /// for this server. - template - OptionDefinitionPtr findOptionDefinition(const std::string& option_space, - const SearchKey& search_key) const; + virtual OptionDefinitionPtr + findOptionDefinition(const std::string& option_space, + const util::Optional& option_code, + const util::Optional& option_name) const; /// @brief Create option instance. /// @@ -185,6 +191,10 @@ public: OptionDataListParser(const uint16_t address_family, CfgOptionDefPtr cfg_option_def = CfgOptionDefPtr()); + /// @brief Virtual destructor. + virtual ~OptionDataListParser() { + } + /// @brief Parses a list of options, instantiates them and stores in cfg /// /// This method expects to get a list of options in option_data_list, @@ -195,7 +205,17 @@ public: /// @param option_data_list configuration that describes the options void parse(const CfgOptionPtr& cfg, isc::data::ConstElementPtr option_data_list); -private: +protected: + + /// @brief Returns an instance of the @c OptionDataListParser to + /// be used in parsing options. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for option data. + /// + /// @return an instance of the @c OptionDataListParser. + virtual boost::shared_ptr createOptionDataParser() const; + /// @brief Address family: @c AF_INET or @c AF_INET6 uint16_t address_family_; diff --git a/src/lib/dhcpsrv/parsers/shared_network_parser.cc b/src/lib/dhcpsrv/parsers/shared_network_parser.cc index 1eb7c8710216d0eec2ab0f2336f6350d349085b7..98c136f9d8c998f09d27833170e9d099744e21ee 100644 --- a/src/lib/dhcpsrv/parsers/shared_network_parser.cc +++ b/src/lib/dhcpsrv/parsers/shared_network_parser.cc @@ -10,12 +10,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include @@ -74,17 +74,17 @@ SharedNetwork4Parser::parse(const data::ConstElementPtr& shared_network_data) { auto json = shared_network_data->get("option-data"); // Create parser instance for option-data. CfgOptionPtr cfg_option = shared_network->getCfgOption(); - OptionDataListParser parser(AF_INET); - parser.parse(cfg_option, json); + auto parser = createOptionDataListParser(); + parser->parse(cfg_option, json); } if (shared_network_data->contains("subnet4")) { auto json = shared_network_data->get("subnet4"); // Create parser instance of subnet4. - Subnets4ListConfigParser parser(check_iface_); + auto parser = createSubnetsListParser(); Subnet4Collection subnets; - parser.parse(subnets, json); + parser->parse(subnets, json); // Add all returned subnets into shared network. for (auto subnet = subnets.cbegin(); subnet != subnets.cend(); @@ -215,6 +215,18 @@ SharedNetwork4Parser::parse(const data::ConstElementPtr& shared_network_data) { return (shared_network); } +boost::shared_ptr +SharedNetwork4Parser::createOptionDataListParser() const { + auto parser = boost::make_shared(AF_INET); + return (parser); +} + +boost::shared_ptr +SharedNetwork4Parser::createSubnetsListParser() const { + auto parser = boost::make_shared(check_iface_); + return (parser); +} + SharedNetwork6Parser::SharedNetwork6Parser(bool check_iface) : check_iface_(check_iface) { } @@ -303,8 +315,8 @@ SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data) { auto json = shared_network_data->get("option-data"); // Create parser instance for option-data. CfgOptionPtr cfg_option = shared_network->getCfgOption(); - OptionDataListParser parser(AF_INET6); - parser.parse(cfg_option, json); + auto parser = createOptionDataListParser(); + parser->parse(cfg_option, json); } if (shared_network_data->contains("client-class")) { @@ -337,9 +349,9 @@ SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data) { auto json = shared_network_data->get("subnet6"); // Create parser instance of subnet6. - Subnets6ListConfigParser parser(check_iface_); + auto parser = createSubnetsListParser(); Subnet6Collection subnets; - parser.parse(subnets, json); + parser->parse(subnets, json); // Add all returned subnets into shared network. for (auto subnet = subnets.cbegin(); subnet != subnets.cend(); @@ -380,5 +392,17 @@ SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data) { return (shared_network); } +boost::shared_ptr +SharedNetwork6Parser::createOptionDataListParser() const { + auto parser = boost::make_shared(AF_INET6); + return (parser); +} + +boost::shared_ptr +SharedNetwork6Parser::createSubnetsListParser() const { + auto parser = boost::make_shared(check_iface_); + return (parser); +} + } // end of namespace isc::dhcp } // end of namespace isc diff --git a/src/lib/dhcpsrv/parsers/shared_network_parser.h b/src/lib/dhcpsrv/parsers/shared_network_parser.h index 1603f856634ad2d1190ce1da12c117e4d7111ede..8b4ea01ec30d44da9953a84adc314038ca24059e 100644 --- a/src/lib/dhcpsrv/parsers/shared_network_parser.h +++ b/src/lib/dhcpsrv/parsers/shared_network_parser.h @@ -1,4 +1,4 @@ -// Copyright (C) 2017-2020 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2017-2021 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include namespace isc { namespace dhcp { @@ -26,6 +29,10 @@ public: /// the system. SharedNetwork4Parser(bool check_iface = true); + /// @brief Virtual destructor. + virtual ~SharedNetwork4Parser() { + } + /// @brief Parses shared configuration information for IPv4 shared network. /// /// @param shared_network_data Data element holding shared network @@ -37,6 +44,25 @@ public: parse(const data::ConstElementPtr& shared_network_data); protected: + + /// @brief Returns an instance of the @c OptionDataListParser to + /// be used in parsing the option-data structure. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for option data. + /// + /// @return an instance of the @c OptionDataListParser(AF_INET). + virtual boost::shared_ptr createOptionDataListParser() const; + + /// @brief Returns an instance of the @c Subnets4ListConfigParser + /// to be used for parsing the subnets within the shared network. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the subnets. + /// + /// @return an instance of the @c Subnets4ListConfigParser. + virtual boost::shared_ptr createSubnetsListParser() const; + /// Check if the specified interface exists in the system. bool check_iface_; }; @@ -50,6 +76,10 @@ public: /// the system. SharedNetwork6Parser(bool check_iface = true); + /// @brief Virtual destructor. + virtual ~SharedNetwork6Parser() { + } + /// @brief Parses shared configuration information for IPv6 shared network. /// /// @param shared_network_data Data element holding shared network @@ -61,6 +91,25 @@ public: parse(const data::ConstElementPtr& shared_network_data); protected: + + /// @brief Returns an instance of the @c OptionDataListParser to + /// be used in parsing the option-data structure. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for option data. + /// + /// @return an instance of the @c OptionDataListParser(AF_INET6). + virtual boost::shared_ptr createOptionDataListParser() const; + + /// @brief Returns an instance of the @c Subnets6ListConfigParser + /// to be used for parsing the subnets within the shared network. + /// + /// This function can be overridden in the child classes to supply + /// a custom parser for the subnets. + /// + /// @return an instance of the @c Subnets6ListConfigParser. + virtual boost::shared_ptr createSubnetsListParser() const; + /// Check if the specified interface exists in the system. bool check_iface_; }; diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc index 1b3a953a5f9bf8ceaa1ce43233a15767f0941a15..8648d97f295ed0e36555a4b49e65869b482d88aa 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc +++ b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc @@ -319,17 +319,24 @@ TestConfigBackendDHCPv4::getAllOptionDefs4(const db::ServerSelector& server_sele OptionDefContainer option_defs; for (auto option_def : option_defs_) { bool got = false; - for (auto tag : tags) { - if (option_def->hasServerTag(ServerTag(tag))) { + if (server_selector.amUnassigned()) { + if (option_def->getServerTags().empty()) { option_defs.push_back(option_def); got = true; - break; + } + } else { + for (auto tag : tags) { + if (option_def->hasServerTag(ServerTag(tag))) { + option_defs.push_back(option_def); + got = true; + break; + } } } if (got) { continue; } - if (option_def->hasAllServerTag()) { + if (option_def->hasAllServerTag() && !server_selector.amUnassigned()) { option_defs.push_back(option_def); } } diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.cc b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.cc index 3afb48c6376763935dba543d549f4ac73dde8697..e59ad5dd668cef0ea5e3c3a2456be1022ae71028 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.cc +++ b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.cc @@ -318,17 +318,24 @@ TestConfigBackendDHCPv6::getAllOptionDefs6(const db::ServerSelector& server_sele OptionDefContainer option_defs; for (auto option_def : option_defs_) { bool got = false; - for (auto tag : tags) { - if (option_def->hasServerTag(ServerTag(tag))) { + if (server_selector.amUnassigned()) { + if (option_def->getServerTags().empty()) { option_defs.push_back(option_def); got = true; - break; + } + } else { + for (auto tag : tags) { + if (option_def->hasServerTag(ServerTag(tag))) { + option_defs.push_back(option_def); + got = true; + break; + } } } if (got) { continue; } - if (option_def->hasAllServerTag()) { + if (option_def->hasAllServerTag() && !server_selector.amUnassigned()) { option_defs.push_back(option_def); } }