From: Thomas Markwalder Date: Mon, 28 Jul 2025 17:48:45 +0000 (-0400) Subject: [#4014] Core and UT for v6 option class-tags X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=9ee137c846750aafedd81103aaf0a5e1c80c4373;p=thirdparty%2Fkea.git [#4014] Core and UT for v6 option class-tags Changes to be committed: modified: doc/sphinx/arm/hooks-cb-cmds.rst modified: src/hooks/dhcp/mysql/mysql_cb_dhcp6.cc modified: src/hooks/dhcp/mysql/mysql_cb_dhcp6.h modified: src/hooks/dhcp/mysql/mysql_cb_impl.cc modified: src/hooks/dhcp/mysql/tests/mysql_cb_dhcp6_unittest.cc modified: src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.cc modified: src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.h modified: src/hooks/dhcp/pgsql/pgsql_cb_impl.cc modified: src/hooks/dhcp/pgsql/tests/pgsql_cb_dhcp6_unittest.cc modified: src/lib/dhcpsrv/config_backend_dhcp6.h modified: src/lib/dhcpsrv/config_backend_pool_dhcp6.cc modified: src/lib/dhcpsrv/config_backend_pool_dhcp6.h modified: src/lib/dhcpsrv/testutils/generic_cb_dhcp4_unittest.h modified: src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.cc modified: src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.h modified: src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc modified: src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h modified: src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.cc modified: src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.h modified: src/share/api/remote-option4-global-del.json modified: src/share/api/remote-option4-global-get.json modified: src/share/api/remote-option4-global-set.json modified: src/share/api/remote-option4-network-del.json modified: src/share/api/remote-option4-network-set.json modified: src/share/api/remote-option4-pool-del.json modified: src/share/api/remote-option4-pool-set.json modified: src/share/api/remote-option4-subnet-del.json modified: src/share/api/remote-option4-subnet-set.json modified: src/share/api/remote-option6-global-del.json modified: src/share/api/remote-option6-global-get.json modified: src/share/api/remote-option6-global-set.json modified: src/share/api/remote-option6-network-del.json modified: src/share/api/remote-option6-network-set.json modified: src/share/api/remote-option6-pd-pool-del.json modified: src/share/api/remote-option6-pd-pool-set.json modified: src/share/api/remote-option6-pool-del.json modified: src/share/api/remote-option6-pool-set.json modified: src/share/api/remote-option6-subnet-del.json --- diff --git a/doc/sphinx/arm/hooks-cb-cmds.rst b/doc/sphinx/arm/hooks-cb-cmds.rst index 68c638c324..5084a15af8 100644 --- a/doc/sphinx/arm/hooks-cb-cmds.rst +++ b/doc/sphinx/arm/hooks-cb-cmds.rst @@ -170,9 +170,9 @@ data content. In order to support this construct, Kea uses the option's ``client-classes`` list in addition to code and space to uniquely identifiy each option. This is important to keep in mind when using the Management API to alter your -configuration. As of Kea 3.1 (applies to DHCPv4 commands only), commands which -get, set, or delete an individual option now accept an optional ``client-classes`` -parameter in addition to ``code`` and ``space`` parameters. +configuration. As of Kea 3.1.1 commands which get, set, or delete an +individual option now accept an optional ``client-classes`` parameter in +addition to ``code`` and ``space`` parameters. If the ``client-classes`` parameter is omitted: @@ -1145,7 +1145,7 @@ The ``remote-option4-global-del``, ``remote-option6-global-del`` Commands These commands are used to delete a global DHCP option from the database. The option is identified by an option code and option space. -As of Kea 3.1, an optional ``client-classes`` parameter may also be +As of Kea 3.1.1 an optional ``client-classes`` parameter may also be specified (see :ref:`cb-cmds-option-class-tags-as-keys`). For example: @@ -1191,7 +1191,7 @@ These commands are used to fetch a global DHCP option from the database. The option is identified by the code and option space. The top-level option spaces where DHCP standard options belong are called "dhcp4" and "dhcp6" for the DHCPv4 and DHCPv6 servers, respectively. -As of Kea 3.1, an optional ``client-classes`` parameter may also be +As of Kea 3.1.1, an optional ``client-classes`` parameter may also be specified (see :ref:`cb-cmds-option-class-tags-as-keys`). The following command retrieves the IPv6 "DNS Servers" (code 23) option @@ -1343,7 +1343,7 @@ The ``remote-option4-network-del``, ``remote-option6-network-del`` Commands These commands are used to delete a shared-network-specific DHCP option from the database. The option is identified by an option code -and option space and as of Kea 3.1, an optional ``client-classes`` +and option space and as of Kea 3.1.1, an optional ``client-classes`` parameter may also be specified (see :ref:`cb-cmds-option-class-tags-as-keys`). These parameters are passed within the ``options`` list. Another list, ``shared-networks``, contains a map @@ -1532,7 +1532,7 @@ The ``remote-option4-pool-del``, ``remote-option6-pool-del`` Commands These commands are used to delete an address-pool-specific DHCP option from the database. The option is identified by an option code -and option space, and as of Kea 3.1, an optional ``client-classes`` parameter +and option space, and as of Kea 3.1.1, an optional ``client-classes`` parameter may also be specified (see :ref:`cb-cmds-option-class-tags-as-keys`). These parameters are passed within the ``options`` list. Another list, ``pools``, contains a map with the @@ -1631,7 +1631,7 @@ The ``remote-option4-subnet-del``, ``remote-option6-subnet-del`` Commands These commands are used to delete a subnet-specific DHCP option from the database. The option is identified by an option code -and option space, and, as of Kea 3.1, an optional ``client-casses`` +and option space, and, as of Kea 3.1.1, an optional ``client-casses`` parameter (see :ref:`cb-cmds-option-class-tags-as-keys`). These parameters are passed within the ``options`` list. Another list, ``subnets``, contains a map with the diff --git a/src/hooks/dhcp/mysql/mysql_cb_dhcp6.cc b/src/hooks/dhcp/mysql/mysql_cb_dhcp6.cc index ab96f4faf4..b5249b23cb 100644 --- a/src/hooks/dhcp/mysql/mysql_cb_dhcp6.cc +++ b/src/hooks/dhcp/mysql/mysql_cb_dhcp6.cc @@ -2175,7 +2175,8 @@ public: MySqlBinding::createNull(), MySqlBinding::createString(tag), MySqlBinding::createInteger(option->option_->getType()), - MySqlBinding::condCreateString(option->space_name_) + MySqlBinding::condCreateString(option->space_name_), + createInputClientClassesBinding(option->client_classes_) }; MySqlTransaction transaction(conn_); @@ -2189,8 +2190,8 @@ public: if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6, in_bindings) == 0) { - // Remove the 3 bindings used only in case of update. - in_bindings.resize(in_bindings.size() - 3); + // Remove the 4 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 4); insertOption6(server_selector, in_bindings); } @@ -2231,7 +2232,8 @@ public: MySqlBinding::createNull(), MySqlBinding::createInteger(static_cast(subnet_id)), MySqlBinding::createInteger(option->option_->getType()), - MySqlBinding::condCreateString(option->space_name_) + MySqlBinding::condCreateString(option->space_name_), + createInputClientClassesBinding(option->client_classes_) }; boost::scoped_ptr transaction; @@ -2252,8 +2254,8 @@ public: if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID, in_bindings) == 0) { - // Remove the 3 bindings used only in case of update. - in_bindings.resize(in_bindings.size() - 3); + // Remove the 4 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 4); insertOption6(server_selector, in_bindings); } @@ -2386,6 +2388,7 @@ public: in_bindings.push_back(MySqlBinding::createInteger(pool_id)); in_bindings.push_back(MySqlBinding::createInteger(option->option_->getType())); in_bindings.push_back(MySqlBinding::condCreateString(option->space_name_)); + in_bindings.push_back(createInputClientClassesBinding(option->client_classes_)); MySqlTransaction transaction(conn_); @@ -2406,8 +2409,8 @@ public: MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID : MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID); if (conn_.updateDeleteQuery(index, in_bindings) == 0) { - // Remove the 3 bindings used only in case of update. - in_bindings.resize(in_bindings.size() - 3); + // Remove the 4 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 4); insertOption6(server_selector, in_bindings); } @@ -2449,7 +2452,8 @@ public: MySqlBinding::createNull(), MySqlBinding::createString(shared_network_name), MySqlBinding::createInteger(option->option_->getType()), - MySqlBinding::condCreateString(option->space_name_) + MySqlBinding::condCreateString(option->space_name_), + createInputClientClassesBinding(option->client_classes_) }; boost::scoped_ptr transaction; @@ -2471,8 +2475,8 @@ public: if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl:: UPDATE_OPTION6_SHARED_NETWORK, in_bindings) == 0) { - // Remove the 3 bindings used only in case of update. - in_bindings.resize(in_bindings.size() - 3); + // Remove the 4 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 4); insertOption6(server_selector, in_bindings); } @@ -2512,7 +2516,8 @@ public: MySqlBinding::createNull(), MySqlBinding::createString(client_class->getName()), MySqlBinding::createInteger(option->option_->getType()), - MySqlBinding::condCreateString(option->space_name_) + MySqlBinding::condCreateString(option->space_name_), + createInputClientClassesBinding(option->client_classes_) }; // Create scoped audit revision. As long as this instance exists @@ -2526,8 +2531,8 @@ public: if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl:: UPDATE_OPTION6_CLIENT_CLASS, in_bindings) == 0) { - // Remove the 3 bindings used only in case of update. - in_bindings.resize(in_bindings.size() - 3); + // Remove the 4 bindings used only in case of update. + in_bindings.resize(in_bindings.size() - 4); insertOption6(server_selector, in_bindings); } } @@ -2612,13 +2617,16 @@ public: /// @param server_selector Server selector. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. /// @return Number of deleted options. uint64_t deleteOption6(const ServerSelector& server_selector, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { MySqlBindingCollection in_bindings = { MySqlBinding::createInteger(code), - MySqlBinding::createString(space) + MySqlBinding::createString(space), + createClientClassesForWhereClause(client_classes) }; // Run DELETE. @@ -2636,15 +2644,18 @@ public: /// belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. /// @return Number of deleted options. uint64_t deleteOption6(const ServerSelector& server_selector, const SubnetID& subnet_id, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { MySqlBindingCollection in_bindings = { MySqlBinding::createInteger(static_cast(subnet_id)), MySqlBinding::createInteger(code), - MySqlBinding::createString(space) + MySqlBinding::createString(space), + createClientClassesForWhereClause(client_classes) }; // Run DELETE. @@ -2662,15 +2673,18 @@ public: /// @param pool_end_address Upper bound pool address. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. /// @return Number of deleted options. uint64_t deleteOption6(const db::ServerSelector& server_selector, const IOAddress& pool_start_address, const IOAddress& pool_end_address, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { MySqlBindingCollection in_bindings = { MySqlBinding::createInteger(code), MySqlBinding::createString(space), + createClientClassesForWhereClause(client_classes), MySqlBinding::createString(pool_start_address.toText()), MySqlBinding::createString(pool_end_address.toText()) }; @@ -2690,15 +2704,18 @@ public: /// @param pd_pool_prefix_length Length of the pd pool prefix. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. /// @return Number of deleted options. uint64_t deleteOption6(const db::ServerSelector& server_selector, const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { MySqlBindingCollection in_bindings = { MySqlBinding::createInteger(code), MySqlBinding::createString(space), + createClientClassesForWhereClause(client_classes), MySqlBinding::createString(pd_pool_prefix.toText()), MySqlBinding::createInteger(pd_pool_prefix_length) }; @@ -2718,15 +2735,18 @@ public: /// option belongs to /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. /// @return Number of deleted options. uint64_t deleteOption6(const db::ServerSelector& server_selector, const std::string& shared_network_name, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { MySqlBindingCollection in_bindings = { MySqlBinding::createString(shared_network_name), MySqlBinding::createInteger(code), - MySqlBinding::createString(space) + MySqlBinding::createString(space), + createClientClassesForWhereClause(client_classes) }; // Run DELETE. @@ -3548,9 +3568,10 @@ TaggedStatementArray tagged_statements = { { MYSQL_GET_OPTION_DEF(dhcp6, AND d.modification_ts >= ?) }, - // Retrieves global option by code and space. + // Retrieves global option by code, space and client-classes. { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE, - MYSQL_GET_OPTION6(AND o.scope_id = 0 AND o.code = ? AND o.space = ?) + MYSQL_GET_OPTION6(AND o.scope_id = 0 AND o.code = ? AND o.space = ? + AND o.client_classes LIKE ?) }, // Retrieves all global options. @@ -3905,32 +3926,38 @@ TaggedStatementArray tagged_statements = { { // Update existing global option. { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6, - MYSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = ? AND o.space = ?) + MYSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = ? AND o.space = ? + AND o.client_classes = ?) }, // Update existing subnet level option. { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID, - MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 1 AND o.dhcp6_subnet_id = ? AND o.code = ? AND o.space = ?) + MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 1 AND o.dhcp6_subnet_id = ? AND o.code = ? AND o.space = ? + AND o.client_classes = ?) }, // Update existing pool level option. { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID, - MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 5 AND o.pool_id = ? AND o.code = ? AND o.space = ?) + MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 5 AND o.pool_id = ? AND o.code = ? AND o.space = ? + AND o.client_classes = ?) }, // Update existing pd pool level option. { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID, - MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 6 AND o.pd_pool_id = ? AND o.code = ? AND o.space = ?) + MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 6 AND o.pd_pool_id = ? AND o.code = ? AND o.space = ? + AND o.client_classes = ?) }, // Update existing shared network level option. { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SHARED_NETWORK, - MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?) + MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? + AND o.space = ? AND o.client_classes = ?) }, // Update existing client class level option. { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_CLIENT_CLASS, - MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = ? AND o.code = ? AND o.space = ?) + MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = ? AND o.code = ? + AND o.space = ? AND o.client_classes = ?) }, // Update existing client class with specifying its position. @@ -4060,7 +4087,8 @@ TaggedStatementArray tagged_statements = { { // Delete single global option. { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6, - MYSQL_DELETE_OPTION_WITH_TAG(dhcp6, AND o.scope_id = 0 AND o.code = ? AND o.space = ?) + MYSQL_DELETE_OPTION_WITH_TAG(dhcp6, AND o.scope_id = 0 AND o.code = ? AND o.space = ? + AND o.client_classes LIKE ?) }, // Delete all global options which are unassigned to any servers. @@ -4071,23 +4099,27 @@ TaggedStatementArray tagged_statements = { { // Delete single option from a subnet. { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SUBNET_ID, MYSQL_DELETE_OPTION_NO_TAG(dhcp6, - WHERE o.scope_id = 1 AND o.dhcp6_subnet_id = ? AND o.code = ? AND o.space = ?) + WHERE o.scope_id = 1 AND o.dhcp6_subnet_id = ? AND o.code = ? AND o.space = ? + AND o.client_classes LIKE ?) }, // Delete single option from a pool. { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_POOL_RANGE, - MYSQL_DELETE_OPTION_POOL_RANGE(dhcp6, o.scope_id = 5 AND o.code = ? AND o.space = ?) + MYSQL_DELETE_OPTION_POOL_RANGE(dhcp6, o.scope_id = 5 AND o.code = ? AND o.space = ? + AND o.client_classes LIKE ?) }, // Delete single option from a pd pool. { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_PD_POOL, - MYSQL_DELETE_OPTION_PD_POOL(o.scope_id = 6 AND o.code = ? AND o.space = ?) + MYSQL_DELETE_OPTION_PD_POOL(o.scope_id = 6 AND o.code = ? AND o.space = ? + AND o.client_classes LIKE ?) }, // Delete single option from a shared network. { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SHARED_NETWORK, MYSQL_DELETE_OPTION_NO_TAG(dhcp6, - WHERE o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?) + WHERE o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ? + AND o.client_classes LIKE ?) }, // Delete options belonging to a subnet. @@ -4296,11 +4328,12 @@ MySqlConfigBackendDHCPv6::getModifiedOptionDefs6(const ServerSelector& server_se OptionDescriptorPtr MySqlConfigBackendDHCPv6::getOption6(const ServerSelector& server_selector, const uint16_t code, - const std::string& space) const { + const std::string& space, + const ClientClassesPtr client_classes) const { LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_OPTION6) .arg(code).arg(space); return (impl_->getOption(MySqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE, - Option::V6, server_selector, code, space)); + Option::V6, server_selector, code, space, client_classes)); } OptionContainer @@ -4658,10 +4691,11 @@ MySqlConfigBackendDHCPv6::deleteAllOptionDefs6(const ServerSelector& server_sele uint64_t MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& server_selector, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION6) .arg(code).arg(space); - uint64_t result = impl_->deleteOption6(server_selector, code, space); + uint64_t result = impl_->deleteOption6(server_selector, code, space, client_classes); LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION6_RESULT) .arg(result); return (result); @@ -4671,14 +4705,15 @@ uint64_t MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */, const std::string& shared_network_name, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { /// @todo In the future we might use the server selector to make sure that the /// option is only deleted if the pool belongs to a given server. For now, we /// just delete it when there is a match with the parent object. LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6) .arg(shared_network_name).arg(code).arg(space); uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), shared_network_name, - code, space); + code, space, client_classes); LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT) .arg(result); return (result); @@ -4688,13 +4723,15 @@ uint64_t MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */, const SubnetID& subnet_id, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { /// @todo In the future we might use the server selector to make sure that the /// option is only deleted if the pool belongs to a given server. For now, we /// just delete it when there is a match with the parent object. LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6) .arg(subnet_id).arg(code).arg(space); - uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), subnet_id, code, space); + uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), subnet_id, code, space, + client_classes); LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT) .arg(result); return (result); @@ -4705,14 +4742,15 @@ MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector const asiolink::IOAddress& pool_start_address, const asiolink::IOAddress& pool_end_address, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { /// @todo In the future we might use the server selector to make sure that the /// option is only deleted if the pool belongs to a given server. For now, we /// just delete it when there is a match with the parent object. LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_OPTION6) .arg(pool_start_address.toText()).arg(pool_end_address.toText()).arg(code).arg(space); uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), pool_start_address, - pool_end_address, code, space); + pool_end_address, code, space, client_classes); LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_OPTION6_RESULT) .arg(result); return (result); @@ -4723,11 +4761,12 @@ MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6) .arg(pd_pool_prefix.toText()).arg(pd_pool_prefix_length).arg(code).arg(space); uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), pd_pool_prefix, - pd_pool_prefix_length, code, space); + pd_pool_prefix_length, code, space, client_classes); LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT) .arg(result); return (result); diff --git a/src/hooks/dhcp/mysql/mysql_cb_dhcp6.h b/src/hooks/dhcp/mysql/mysql_cb_dhcp6.h index 22b9f615a7..97d0682630 100644 --- a/src/hooks/dhcp/mysql/mysql_cb_dhcp6.h +++ b/src/hooks/dhcp/mysql/mysql_cb_dhcp6.h @@ -146,12 +146,17 @@ public: /// @brief Retrieves single option by code and space. /// /// @param server_selector Server selector. + /// @param code code of the option to be deleted. + /// @param space option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Pointer to the retrieved option descriptor or null if /// no option was found. /// @throw NotImplemented if server selector is "unassigned". virtual OptionDescriptorPtr getOption6(const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space) const; + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()) const; /// @brief Retrieves all global options. /// @@ -479,11 +484,14 @@ public: /// @param server_selector Server selector. /// @param code Code of the option to be deleted. /// @param space Option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. /// @throw NotImplemented if server selector is "unassigned". virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes shared network level option. /// @@ -492,12 +500,16 @@ public: /// option belongs to /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. + /// @return Number of deleted options. /// @throw NotImplemented if server selector is "unassigned". virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const std::string& shared_network_name, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes subnet level option. /// @@ -506,11 +518,16 @@ public: /// belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. /// @throw NotImplemented if server selector is "unassigned". virtual uint64_t - deleteOption6(const db::ServerSelector& server_selector, const SubnetID& subnet_id, - const uint16_t code, const std::string& space); + deleteOption6(const db::ServerSelector& server_selector, + const SubnetID& subnet_id, + const uint16_t code, + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes pool level option. /// @@ -521,6 +538,8 @@ public: /// deleted option belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. /// @throw NotImplemented if server selector is "unassigned". virtual uint64_t @@ -528,7 +547,8 @@ public: const asiolink::IOAddress& pool_start_address, const asiolink::IOAddress& pool_end_address, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes prefix delegation pool level option. /// @@ -539,6 +559,8 @@ public: /// delegation pool to which the deleted option belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. /// @throw NotImplemented if server selector is "unassigned". virtual uint64_t @@ -546,7 +568,8 @@ public: const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes global parameter. /// diff --git a/src/hooks/dhcp/mysql/mysql_cb_impl.cc b/src/hooks/dhcp/mysql/mysql_cb_impl.cc index ebf2d74dc0..4418fccfbf 100644 --- a/src/hooks/dhcp/mysql/mysql_cb_impl.cc +++ b/src/hooks/dhcp/mysql/mysql_cb_impl.cc @@ -580,11 +580,8 @@ MySqlConfigBackendImpl::getOption(const int index, in_bindings.push_back(MySqlBinding::createInteger(code)); } in_bindings.push_back(MySqlBinding::createString(space)); + in_bindings.push_back(createClientClassesForWhereClause(client_classes)); - /// @todo TKM Remove the if when v6 is ready. - if (universe == Option::V4) { - in_bindings.push_back(createClientClassesForWhereClause(client_classes)); - } getOptions(index, in_bindings, universe, options); return (options.empty() ? OptionDescriptorPtr() : OptionDescriptor::create(*options.begin())); diff --git a/src/hooks/dhcp/mysql/tests/mysql_cb_dhcp6_unittest.cc b/src/hooks/dhcp/mysql/tests/mysql_cb_dhcp6_unittest.cc index 3580dfa6e7..7a5bdf6901 100644 --- a/src/hooks/dhcp/mysql/tests/mysql_cb_dhcp6_unittest.cc +++ b/src/hooks/dhcp/mysql/tests/mysql_cb_dhcp6_unittest.cc @@ -335,6 +335,14 @@ TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedOptionDefs6Test) { getModifiedOptionDefs6Test(); } +TEST_F(MySqlConfigBackendDHCPv6Test, globalOption6WithClientClassesTest) { + globalOption6WithClientClassesTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, getAllOptions6WithClientClassesTest) { + getAllOptions6WithClientClassesTest(); +} + TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateDeleteOption6Test) { createUpdateDeleteOption6Test(); } @@ -407,6 +415,22 @@ TEST_F(MySqlConfigBackendDHCPv6Test, multipleAuditEntriesTest) { multipleAuditEntriesTest(); } +TEST_F(MySqlConfigBackendDHCPv6Test, sharedNetworkOption6WithClientClassesTest) { + sharedNetworkOption6WithClientClassesTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, subnetOption6WithClientClassesTest) { + subnetOption6WithClientClassesTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, poolOption6WithClientClassesTest) { + poolOption6WithClientClassesTest(); +} + +TEST_F(MySqlConfigBackendDHCPv6Test, pdPoolOption6WithClientClassesTest) { + pdPoolOption6WithClientClassesTest(); +} + /// @brief Test fixture for verifying database connection loss-recovery /// behavior. class MySqlConfigBackendDHCPv6DbLostCallbackTest : public GenericConfigBackendDbLostCallbackTest { diff --git a/src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.cc b/src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.cc index 424d847f43..3528292a37 100644 --- a/src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.cc +++ b/src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.cc @@ -1926,6 +1926,7 @@ public: in_bindings.add(tag); in_bindings.add(option->option_->getType()); in_bindings.addOptional(option->space_name_); + addClientClassesBinding(in_bindings, option->client_classes_); // Start transaction. PgSqlTransaction transaction(conn_); @@ -1996,6 +1997,7 @@ public: in_bindings.add(subnet_id); in_bindings.add(option->option_->getType()); in_bindings.addOptional(option->space_name_); + addClientClassesBinding(in_bindings, option->client_classes_); // Start transaction. PgSqlTransaction transaction(conn_); @@ -2147,6 +2149,7 @@ public: in_bindings.add(pool_id); in_bindings.add(option->option_->getType()); in_bindings.addOptional(option->space_name_); + addClientClassesBinding(in_bindings, option->client_classes_); // Start transaction. PgSqlTransaction transaction(conn_); @@ -2227,6 +2230,7 @@ public: in_bindings.add(shared_network_name); in_bindings.add(option->option_->getType()); in_bindings.addOptional(option->space_name_); + addClientClassesBinding(in_bindings, option->client_classes_); // Start transaction. PgSqlTransaction transaction(conn_); @@ -2295,6 +2299,7 @@ public: in_bindings.add(class_name); in_bindings.add(option->option_->getType()); in_bindings.addOptional(option->space_name_); + addClientClassesBinding(in_bindings, option->client_classes_); // Create scoped audit revision. As long as this instance exists // no new audit revisions are created in any subsequent calls. @@ -2397,13 +2402,16 @@ public: /// @param server_selector Server selector. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. /// @return Number of deleted options. uint64_t deleteOption6(const ServerSelector& server_selector, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { PsqlBindArray in_bindings; in_bindings.add(code); in_bindings.add(space); + addClientClassesForWhereClause(in_bindings, client_classes); // Run DELETE. return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6, @@ -2421,15 +2429,18 @@ public: /// belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. /// @return Number of deleted options. uint64_t deleteOption6(const ServerSelector& server_selector, const SubnetID& subnet_id, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { PsqlBindArray in_bindings; in_bindings.add(subnet_id); in_bindings.add(code); in_bindings.add(space); + addClientClassesForWhereClause(in_bindings, client_classes); // Run DELETE. return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SUBNET_ID, @@ -2447,17 +2458,20 @@ public: /// @param pool_end_address Upper bound pool address. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. /// @return Number of deleted options. uint64_t deleteOption6(const db::ServerSelector& server_selector, const IOAddress& pool_start_address, const IOAddress& pool_end_address, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { PsqlBindArray in_bindings; in_bindings.addInet6(pool_start_address); in_bindings.addInet6(pool_end_address); in_bindings.add(code); in_bindings.add(space); + addClientClassesForWhereClause(in_bindings, client_classes); // Run DELETE. return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_POOL_RANGE, @@ -2475,17 +2489,20 @@ public: /// @param pd_pool_prefix_length Length of the pd pool prefix. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. /// @return Number of deleted options. uint64_t deleteOption6(const db::ServerSelector& server_selector, const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { PsqlBindArray in_bindings; in_bindings.addTempString(pd_pool_prefix.toText()); in_bindings.add(pd_pool_prefix_length); in_bindings.add(code); in_bindings.add(space); + addClientClassesForWhereClause(in_bindings, client_classes); // Run DELETE. return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_PD_POOL, @@ -2503,15 +2520,18 @@ public: /// option belongs to /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. /// @return Number of deleted options. uint64_t deleteOption6(const db::ServerSelector& server_selector, const std::string& shared_network_name, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { PsqlBindArray in_bindings; in_bindings.add(shared_network_name); in_bindings.add(code); in_bindings.add(space); + addClientClassesForWhereClause(in_bindings, client_classes); // Run DELETE. return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SHARED_NETWORK, @@ -3552,14 +3572,16 @@ TaggedStatementArray tagged_statements = { { // Retrieves global option by code and space. { // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE, - 3, + 4, { OID_VARCHAR, // 1 server_tag OID_INT2, // 2 code - OID_VARCHAR // 3 space + OID_VARCHAR, // 3 space + OID_TEXT // 4 client_classes }, "GET_OPTION6_CODE_SPACE", - PGSQL_GET_OPTION6(AND o.scope_id = 0 AND o.code = $2 AND o.space = $3) + PGSQL_GET_OPTION6(AND o.scope_id = 0 AND o.code = $2 AND o.space = $3 + AND o.client_classes LIKE $4) }, // Retrieves all global options. @@ -4417,7 +4439,7 @@ TaggedStatementArray tagged_statements = { { // Update existing global option. { // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6, - 18, + 19, { OID_INT2, // 1 code OID_BYTEA, // 2 value @@ -4437,15 +4459,17 @@ TaggedStatementArray tagged_statements = { { OID_VARCHAR, // 16 server_tag OID_INT2, // 17 code (of option to update) OID_VARCHAR, // 18 space (of option to update) + OID_TEXT // 19 client_classes (of option to update) }, "UPDATE_OPTION6", - PGSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = $17 AND o.space = $18) + PGSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = $17 AND o.space = $18 + AND o.client_classes = $19) }, // Update existing subnet level option. { // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID, - 18, + 19, { OID_INT2, // 1 code OID_BYTEA, // 2 value @@ -4464,16 +4488,18 @@ TaggedStatementArray tagged_statements = { { OID_INT8, // 15 pd_pool_id OID_INT8, // 16 subnet_id (of option to update) OID_INT2, // 17 code (of option to update) - OID_VARCHAR // 18 space (of option to update) + OID_VARCHAR, // 18 space (of option to update) + OID_TEXT // 19 client_classes (of option to update) }, "UPDATE_OPTION6_SUBNET_ID", - PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 1 AND o.dhcp6_subnet_id = $16 AND o.code = $17 AND o.space = $18) + PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 1 AND o.dhcp6_subnet_id = $16 AND o.code = $17 + AND o.space = $18 AND o.client_classes = $19) }, // Update existing pool level option. { // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID, - 18, + 19, { OID_INT2, // 1 code OID_BYTEA, // 2 value @@ -4492,16 +4518,18 @@ TaggedStatementArray tagged_statements = { { OID_INT8, // 15 pd_pool_id OID_INT8, // 16 pool_id (of option to update) OID_INT2, // 17 code (of option to update) - OID_VARCHAR // 18 space (of option to update) + OID_VARCHAR, // 18 space (of option to update) + OID_TEXT // 19 client_classes (of option to update) }, "UPDATE_OPTION6_POOL_ID", - PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 5 AND o.pool_id = $16 AND o.code = $17 AND o.space = $18) + PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 5 AND o.pool_id = $16 AND o.code = $17 + AND o.space = $18 AND o.client_classes = $19) }, // Update existing pd pool level option. { // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID, - 18, + 19, { OID_INT2, // 1 code OID_BYTEA, // 2 value @@ -4520,16 +4548,18 @@ TaggedStatementArray tagged_statements = { { OID_INT8, // 15 pd_pool_id OID_INT8, // 16 pd_pool_id (of option to update) OID_INT2, // 17 code (of option to update) - OID_VARCHAR // 18 space (of option to update) + OID_VARCHAR, // 18 space (of option to update) + OID_TEXT // 19 client_classes (of option to update) }, "UPDATE_OPTION6_PD_POOL_ID", - PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 6 AND o.pd_pool_id = $16 AND o.code = $17 AND o.space = $18) + PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 6 AND o.pd_pool_id = $16 AND o.code = $17 + AND o.space = $18 AND o.client_classes = $19) }, // Update existing shared network level option. { // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SHARED_NETWORK, - 18, + 19, { OID_INT2, // 1 code OID_BYTEA, // 2 value @@ -4548,16 +4578,18 @@ TaggedStatementArray tagged_statements = { { OID_INT8, // 15 pd_pool_id OID_VARCHAR, // 16 shared_network_name (of option to update) OID_INT2, // 17 code (of option to update) - OID_VARCHAR // 18 space (of option to update) + OID_VARCHAR, // 18 space (of option to update) + OID_TEXT // 19 client_classes (of option to update) }, "UPDATE_OPTION6_SHARED_NETWORK", - PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = $16 AND o.code = $17 AND o.space = $18) + PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = $16 AND o.code = $17 + AND o.space = $18 AND o.client_classes = $19) }, // Update existing client class level option. { // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_CLIENT_CLASS, - 18, + 19, { OID_INT2, // 1 code OID_BYTEA, // 2 value @@ -4576,10 +4608,12 @@ TaggedStatementArray tagged_statements = { { OID_INT8, // 15 pd_pool_id OID_VARCHAR, // 16 client_class (of option to update) OID_INT2, // 17 code (of option to update) - OID_VARCHAR // 18 space (of option to update) + OID_VARCHAR, // 18 space (of option to update) + OID_TEXT // 19 client_classes (of option to update) }, "UPDATE_OPTION6_CLIENT_CLASS", - PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = $16 AND o.code = $17 AND o.space = $18) + PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = $16 AND o.code = $17 + AND o.space = $18 AND o.client_classes = $19) }, // Update existing client class with specifying its position. @@ -4897,14 +4931,16 @@ TaggedStatementArray tagged_statements = { { // Delete single global option. { // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6, - 3, + 4, { OID_VARCHAR, // 1 server_tag OID_INT2, // 2 code - OID_VARCHAR // 3 space + OID_VARCHAR, // 3 space + OID_TEXT // 4 client_classes }, "DELETE_OPTION6", - PGSQL_DELETE_OPTION_WITH_TAG(dhcp6, AND o.scope_id = 0 AND o.code = $2 AND o.space = $3) + PGSQL_DELETE_OPTION_WITH_TAG(dhcp6, AND o.scope_id = 0 AND o.code = $2 AND o.space = $3 + AND o.client_classes LIKE $4) }, // Delete all global options which are unassigned to any servers. @@ -4921,57 +4957,65 @@ TaggedStatementArray tagged_statements = { { // Delete single option from a subnet. { // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SUBNET_ID, - 3, + 4, { - OID_INT8, // 1 subnet_id - OID_INT2, // 2 code - OID_VARCHAR // 3 space + OID_INT8, // 1 subnet_id + OID_INT2, // 2 code + OID_VARCHAR, // 3 space + OID_TEXT // 4 client_classes }, "DELETE_OPTION6_SUBNET_ID", PGSQL_DELETE_OPTION_NO_TAG(dhcp6, - WHERE o.scope_id = 1 AND o.dhcp6_subnet_id = $1 AND o.code = $2 AND o.space = $3) + WHERE o.scope_id = 1 AND o.dhcp6_subnet_id = $1 AND o.code = $2 AND o.space = $3 + AND o.client_classes LIKE $4) }, // Delete single option from a pool. { // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_POOL_RANGE, - 4, + 5, { - OID_TEXT, // 1 start_address - cast as inet - OID_TEXT, // 2 start_address - cast as inet - OID_INT2, // 3 code - OID_VARCHAR // 4 space + OID_TEXT, // 1 start_address - cast as inet + OID_TEXT, // 2 start_address - cast as inet + OID_INT2, // 3 code + OID_VARCHAR, // 4 space + OID_TEXT // 5 client_classes }, "DELETE_OPTION6_POOL_RANGE", - PGSQL_DELETE_OPTION_POOL_RANGE(dhcp6, o.scope_id = 5 AND o.code = $3 AND o.space = $4) + PGSQL_DELETE_OPTION_POOL_RANGE(dhcp6, o.scope_id = 5 AND o.code = $3 AND o.space = $4 + AND o.client_classes LIKE $5) }, // Delete single option from a pd pool. { // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_PD_POOL, - 4, + 5, { - OID_TEXT, // 1 prefix - OID_INT2, // 2 prefix_length - OID_INT2, // 3 code - OID_VARCHAR // 4 space + OID_TEXT, // 1 prefix + OID_INT2, // 2 prefix_length + OID_INT2, // 3 code + OID_VARCHAR, // 4 space + OID_TEXT // 5 client_classes }, "DELETE_OPTION6_PD_POOL", - PGSQL_DELETE_OPTION_PD_POOL(o.scope_id = 6 AND o.code = $3 AND o.space = $4) + PGSQL_DELETE_OPTION_PD_POOL(o.scope_id = 6 AND o.code = $3 AND o.space = $4 + AND o.client_classes LIKE $5) }, // Delete single option from a shared network. { // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SHARED_NETWORK, - 3, + 4, { OID_VARCHAR, // 1 shared_network_name OID_INT2, // 2 code - OID_VARCHAR // 3 space + OID_VARCHAR, // 3 space + OID_TEXT // 4 client_classes }, "DELETE_OPTION6_SHARED_NETWORK", PGSQL_DELETE_OPTION_NO_TAG(dhcp6, - WHERE o.scope_id = 4 AND o.shared_network_name = $1 AND o.code = $2 AND o.space = $3) + WHERE o.scope_id = 4 AND o.shared_network_name = $1 AND o.code = $2 AND o.space = $3 + AND o.client_classes LIKE $4) }, // Delete options belonging to a subnet. @@ -5272,11 +5316,12 @@ PgSqlConfigBackendDHCPv6::getModifiedOptionDefs6(const ServerSelector& server_se OptionDescriptorPtr PgSqlConfigBackendDHCPv6::getOption6(const ServerSelector& server_selector, const uint16_t code, - const std::string& space) const { + const std::string& space, + const ClientClassesPtr client_classes) const { LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_OPTION6) .arg(code).arg(space); return (impl_->getOption(PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE, - Option::V6, server_selector, code, space)); + Option::V6, server_selector, code, space, client_classes)); } OptionContainer @@ -5635,10 +5680,11 @@ PgSqlConfigBackendDHCPv6::deleteAllOptionDefs6(const ServerSelector& server_sele uint64_t PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& server_selector, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION6) .arg(code).arg(space); - uint64_t result = impl_->deleteOption6(server_selector, code, space); + uint64_t result = impl_->deleteOption6(server_selector, code, space, client_classes); LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION6_RESULT) .arg(result); return (result); @@ -5648,14 +5694,15 @@ uint64_t PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */, const std::string& shared_network_name, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { /// @todo In the future we might use the server selector to make sure that the /// option is only deleted if the pool belongs to a given server. For now, we /// just delete it when there is a match with the parent object. LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6) .arg(shared_network_name).arg(code).arg(space); uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), shared_network_name, - code, space); + code, space, client_classes); LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT) .arg(result); return (result); @@ -5665,13 +5712,15 @@ uint64_t PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */, const SubnetID& subnet_id, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { /// @todo In the future we might use the server selector to make sure that the /// option is only deleted if the pool belongs to a given server. For now, we /// just delete it when there is a match with the parent object. LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6) .arg(subnet_id).arg(code).arg(space); - uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), subnet_id, code, space); + uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), subnet_id, code, space, + client_classes); LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT) .arg(result); return (result); @@ -5682,14 +5731,15 @@ PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector const asiolink::IOAddress& pool_start_address, const asiolink::IOAddress& pool_end_address, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { /// @todo In the future we might use the server selector to make sure that the /// option is only deleted if the pool belongs to a given server. For now, we /// just delete it when there is a match with the parent object. LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_OPTION6) .arg(pool_start_address.toText()).arg(pool_end_address.toText()).arg(code).arg(space); uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), pool_start_address, - pool_end_address, code, space); + pool_end_address, code, space, client_classes); LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT) .arg(result); return (result); @@ -5700,11 +5750,12 @@ PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6) .arg(pd_pool_prefix.toText()).arg(pd_pool_prefix_length).arg(code).arg(space); uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), pd_pool_prefix, - pd_pool_prefix_length, code, space); + pd_pool_prefix_length, code, space, client_classes); LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT) .arg(result); return (result); diff --git a/src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.h b/src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.h index 056d722bfb..44f8c5529a 100644 --- a/src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.h +++ b/src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.h @@ -146,12 +146,17 @@ public: /// @brief Retrieves single option by code and space. /// /// @param server_selector Server selector. + /// @param code Code of the option to be deleted. + /// @param space Option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Pointer to the retrieved option descriptor or null if /// no option was found. /// @throw NotImplemented if server selector is "unassigned". virtual OptionDescriptorPtr getOption6(const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space) const; + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()) const; /// @brief Retrieves all global options. /// @@ -479,11 +484,14 @@ public: /// @param server_selector Server selector. /// @param code Code of the option to be deleted. /// @param space Option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. /// @throw NotImplemented if server selector is "unassigned". virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes shared network level option. /// @@ -492,12 +500,16 @@ public: /// option belongs to /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. + /// @return Number of deleted options. /// @throw NotImplemented if server selector is "unassigned". virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const std::string& shared_network_name, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes subnet level option. /// @@ -506,11 +518,14 @@ public: /// belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. /// @throw NotImplemented if server selector is "unassigned". virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const SubnetID& subnet_id, - const uint16_t code, const std::string& space); + const uint16_t code, const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes pool level option. /// @@ -521,6 +536,8 @@ public: /// deleted option belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. /// @throw NotImplemented if server selector is "unassigned". virtual uint64_t @@ -528,7 +545,8 @@ public: const asiolink::IOAddress& pool_start_address, const asiolink::IOAddress& pool_end_address, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes prefix delegation pool level option. /// @@ -539,6 +557,8 @@ public: /// delegation pool to which the deleted option belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. /// @throw NotImplemented if server selector is "unassigned". virtual uint64_t @@ -546,7 +566,8 @@ public: const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes global parameter. /// diff --git a/src/hooks/dhcp/pgsql/pgsql_cb_impl.cc b/src/hooks/dhcp/pgsql/pgsql_cb_impl.cc index c41995ce74..5e8a0e103d 100644 --- a/src/hooks/dhcp/pgsql/pgsql_cb_impl.cc +++ b/src/hooks/dhcp/pgsql/pgsql_cb_impl.cc @@ -561,10 +561,7 @@ PgSqlConfigBackendImpl::getOption(const int index, in_bindings.add(tag); in_bindings.add(code); in_bindings.add(space); - /// @todo TKM remove if when v6 is ready. - if (universe == Option::V4) { - addClientClassesForWhereClause(in_bindings, client_classes); - } + addClientClassesForWhereClause(in_bindings, client_classes); getOptions(index, in_bindings, universe, options); return (options.empty() ? OptionDescriptorPtr() : diff --git a/src/hooks/dhcp/pgsql/tests/pgsql_cb_dhcp6_unittest.cc b/src/hooks/dhcp/pgsql/tests/pgsql_cb_dhcp6_unittest.cc index df80329638..4b5ff7019e 100644 --- a/src/hooks/dhcp/pgsql/tests/pgsql_cb_dhcp6_unittest.cc +++ b/src/hooks/dhcp/pgsql/tests/pgsql_cb_dhcp6_unittest.cc @@ -349,6 +349,15 @@ TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedOptions6Test) { getModifiedOptions6Test(); } + +TEST_F(PgSqlConfigBackendDHCPv6Test, globalOption6WithClientClassesTest) { + globalOption6WithClientClassesTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, getAllOptions6WithClientClassesTest) { + getAllOptions6WithClientClassesTest(); +} + TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteSubnetOption6Test) { createUpdateDeleteSubnetOption6Test(); } @@ -405,6 +414,22 @@ TEST_F(PgSqlConfigBackendDHCPv6Test, multipleAuditEntriesTest) { multipleAuditEntriesTest(); } +TEST_F(PgSqlConfigBackendDHCPv6Test, sharedNetworkOption6WithClientClassesTest) { + sharedNetworkOption6WithClientClassesTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, subnetOption6WithClientClassesTest) { + subnetOption6WithClientClassesTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, poolOption6WithClientClassesTest) { + poolOption6WithClientClassesTest(); +} + +TEST_F(PgSqlConfigBackendDHCPv6Test, pdPoolOption6WithClientClassesTest) { + pdPoolOption6WithClientClassesTest(); +} + /// @brief Test fixture for verifying database connection loss-recovery /// behavior. class PgSqlConfigBackendDHCPv6DbLostCallbackTest : public GenericConfigBackendDbLostCallbackTest { diff --git a/src/lib/dhcpsrv/config_backend_dhcp6.h b/src/lib/dhcpsrv/config_backend_dhcp6.h index 37a7e7f6c8..9275585f0a 100644 --- a/src/lib/dhcpsrv/config_backend_dhcp6.h +++ b/src/lib/dhcpsrv/config_backend_dhcp6.h @@ -230,11 +230,14 @@ public: /// @param server_selector Server selector. /// @param code Option code. /// @param space Option space. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Pointer to the retrieved option descriptor or null if /// no option was found. virtual OptionDescriptorPtr getOption6(const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space) const = 0; + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()) const = 0; /// @brief Retrieves all global options. /// @@ -588,11 +591,14 @@ public: /// @param server_selector Server selector. /// @param code Code of the option to be deleted. /// @param space Option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space) = 0; + const std::string& space, + ClientClassesPtr client_classes = ClientClassesPtr()) = 0; /// @brief Deletes shared network level option. /// @@ -604,11 +610,15 @@ public: /// belongs to. /// @param code Code of the option to be deleted. /// @param space Option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. + /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::ServerSelector& selector, const std::string& shared_network_name, const uint16_t code, - const std::string& space) = 0; + const std::string& space, + ClientClassesPtr client_classes = ClientClassesPtr()) = 0; /// @brief Deletes subnet level option. /// @@ -620,12 +630,15 @@ public: /// belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const SubnetID& subnet_id, const uint16_t code, - const std::string& space) = 0; + const std::string& space, + ClientClassesPtr client_classes = ClientClassesPtr()) = 0; /// @brief Deletes pool level option. /// @@ -639,13 +652,16 @@ public: /// deleted option belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const asiolink::IOAddress& pool_start_address, const asiolink::IOAddress& pool_end_address, const uint16_t code, - const std::string& space) = 0; + const std::string& space, + ClientClassesPtr client_classes = ClientClassesPtr()) = 0; /// @brief Deletes prefix delegation pool level option. /// @@ -659,13 +675,16 @@ public: /// pool to which the deleted option belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space) = 0; + const std::string& space, + ClientClassesPtr client_classes = ClientClassesPtr()) = 0; /// @brief Deletes global parameter. /// diff --git a/src/lib/dhcpsrv/config_backend_pool_dhcp6.cc b/src/lib/dhcpsrv/config_backend_pool_dhcp6.cc index 05513e12cb..405d59e996 100644 --- a/src/lib/dhcpsrv/config_backend_pool_dhcp6.cc +++ b/src/lib/dhcpsrv/config_backend_pool_dhcp6.cc @@ -138,11 +138,13 @@ OptionDescriptorPtr ConfigBackendPoolDHCPv6::getOption6(const BackendSelector& backend_selector, const ServerSelector& server_selector, const uint16_t code, - const std::string& space) const { + const std::string& space, + const ClientClassesPtr client_classes + /* = ClientClassesPtr() */) const { OptionDescriptorPtr option; getPropertyPtrConst (&ConfigBackendDHCPv6::getOption6, backend_selector, server_selector, - option, code, space); + option, code, space, client_classes); return (option); } @@ -443,10 +445,13 @@ uint64_t ConfigBackendPoolDHCPv6::deleteOption6(const BackendSelector& backend_selector, const ServerSelector& server_selector, const uint16_t code, - const std::string& space) { - return (createUpdateDeleteProperty + const std::string& space, + const ClientClassesPtr client_classes + /* = ClientClassesPtr() */) { + return (createUpdateDeleteProperty (&ConfigBackendDHCPv6::deleteOption6, backend_selector, server_selector, - code, space)); + code, space, client_classes)); } uint64_t @@ -454,11 +459,14 @@ ConfigBackendPoolDHCPv6::deleteOption6(const BackendSelector& backend_selector, const ServerSelector& server_selector, const std::string& shared_network_name, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes + /* = ClientClassesPtr() */) { return (createUpdateDeleteProperty + const std::string&, + const ClientClassesPtr> (&ConfigBackendDHCPv6::deleteOption6, backend_selector, server_selector, - shared_network_name, code, space)); + shared_network_name, code, space, client_classes)); } uint64_t @@ -466,10 +474,14 @@ ConfigBackendPoolDHCPv6::deleteOption6(const BackendSelector& backend_selector, const ServerSelector& server_selector, const SubnetID& subnet_id, const uint16_t code, - const std::string& space) { - return (createUpdateDeleteProperty + const std::string& space, + const ClientClassesPtr client_classes + /* = ClientClassesPtr() */) { + return (createUpdateDeleteProperty (&ConfigBackendDHCPv6::deleteOption6, backend_selector, server_selector, - subnet_id, code, space)); + subnet_id, code, space, client_classes)); } uint64_t @@ -478,11 +490,14 @@ ConfigBackendPoolDHCPv6::deleteOption6(const BackendSelector& backend_selector, const asiolink::IOAddress& pool_start_address, const asiolink::IOAddress& pool_end_address, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes + /* = ClientClassesPtr() */) { return (createUpdateDeleteProperty + uint16_t, const std::string&, + const ClientClassesPtr> (&ConfigBackendDHCPv6::deleteOption6, backend_selector, server_selector, - pool_start_address, pool_end_address, code, space)); + pool_start_address, pool_end_address, code, space, client_classes)); } uint64_t @@ -491,11 +506,14 @@ ConfigBackendPoolDHCPv6::deleteOption6(const BackendSelector& backend_selector, const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes + /* = ClientClassesPtr() */) { return (createUpdateDeleteProperty + uint16_t, const std::string&, + const ClientClassesPtr> (&ConfigBackendDHCPv6::deleteOption6, backend_selector, server_selector, - pd_pool_prefix, pd_pool_prefix_length, code, space)); + pd_pool_prefix, pd_pool_prefix_length, code, space, client_classes)); } uint64_t diff --git a/src/lib/dhcpsrv/config_backend_pool_dhcp6.h b/src/lib/dhcpsrv/config_backend_pool_dhcp6.h index c8660000d8..e122beb959 100644 --- a/src/lib/dhcpsrv/config_backend_pool_dhcp6.h +++ b/src/lib/dhcpsrv/config_backend_pool_dhcp6.h @@ -165,13 +165,16 @@ public: /// @param server_selector Server selector. /// @param code Option code. /// @param space Option space. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Pointer to the retrieved option descriptor or null if /// no option was found. virtual OptionDescriptorPtr getOption6(const db::BackendSelector& backend_selector, const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space) const; + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()) const; /// @brief Retrieves all global options. /// @@ -513,12 +516,15 @@ public: /// @param server_selector Server selector. /// @param code Code of the option to be deleted. /// @param space Option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::BackendSelector& backend_selector, const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes shared network level option. /// @@ -528,12 +534,16 @@ public: /// belongs to. /// @param code Code of the option to be deleted. /// @param space Option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. + /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::BackendSelector& backend_selector, const db::ServerSelector& server_selector, const std::string& shared_network_name, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes subnet level option. /// @@ -543,12 +553,15 @@ public: /// belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::BackendSelector& backend_selector, const db::ServerSelector& server_selector, const SubnetID& subnet_id, - const uint16_t code, const std::string& space); + const uint16_t code, const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes pool level option. /// @@ -567,7 +580,8 @@ public: const asiolink::IOAddress& pool_start_address, const asiolink::IOAddress& pool_end_address, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes prefix delegation pool level option. /// @@ -579,6 +593,8 @@ public: /// pool to which the deleted option belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::BackendSelector& backend_selector, @@ -586,7 +602,8 @@ public: const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes global parameter. /// diff --git a/src/lib/dhcpsrv/testutils/generic_cb_dhcp4_unittest.h b/src/lib/dhcpsrv/testutils/generic_cb_dhcp4_unittest.h index 4a89d5cd89..9dc1408051 100644 --- a/src/lib/dhcpsrv/testutils/generic_cb_dhcp4_unittest.h +++ b/src/lib/dhcpsrv/testutils/generic_cb_dhcp4_unittest.h @@ -316,7 +316,7 @@ public: void getModifiedOptions4Test(); /// @brief Creates a list of string options with and without client_class tags. - /// It creates 3 DHO_TCODE options and 2 DHO_PCODE options. + /// It creates 2 DHO_TCODE options and 3 DHO_PCODE options. std::list makeClassTaggedOptions(); /// @brief Updates the value of each string option in the list. diff --git a/src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.cc b/src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.cc index 726e5f98a7..0056724bf2 100644 --- a/src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.cc +++ b/src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.cc @@ -74,8 +74,12 @@ GenericConfigBackendDHCPv6Test::SetUp() { void GenericConfigBackendDHCPv6Test::TearDown() { cbptr_.reset(); - // If data wipe enabled, delete transient data otherwise destroy the schema. - destroySchema(); + if (getenv("KEA_UNIT_TEST_KEEP_SCHEMA")) { + std::cout << "KEA_UNIT_TEST_KEEP_SCHEMA set, avoid schema destruction" << std::endl; + } else { + // If data wipe enabled, delete transient data otherwise destroy the schema. + destroySchema(); + } } db::AuditEntryCollection @@ -3659,6 +3663,212 @@ GenericConfigBackendDHCPv6Test::getModifiedOptions6Test() { } } +std::list +GenericConfigBackendDHCPv6Test::makeClassTaggedOptions() { + // Describes an option to create. + struct OptData { + uint16_t code_; + std::string value_; + std::string cclass_; + }; + + // List of options to create. + // Using timezone options as they are handy string options. + std::list opts_to_make = { + { D6O_NEW_TZDB_TIMEZONE, "T100", "cc-one" }, + { D6O_NEW_POSIX_TIMEZONE, "P100", "cc-one" }, + { D6O_NEW_POSIX_TIMEZONE, "P300", "" }, + { D6O_NEW_TZDB_TIMEZONE, "T200", "" }, + { D6O_NEW_POSIX_TIMEZONE, "P200", "cc-two" } + }; + + std::list tagged_options; + for (auto const& opt_to_make : opts_to_make) { + OptionDescriptor desc = createOption(Option::V6, opt_to_make.code_, + true, false, false, opt_to_make.value_); + desc.space_name_ = DHCP6_OPTION_SPACE; + if (!opt_to_make.cclass_.empty()) { + desc.addClientClass(opt_to_make.cclass_); + } + + tagged_options.push_back(OptionDescriptorPtr(new OptionDescriptor(desc))); + } + + return (tagged_options); +} + +void +GenericConfigBackendDHCPv6Test::updateClassTaggedOptions( + std::list& options) { + for (auto& desc : options) { + OptionStringPtr opt = boost::dynamic_pointer_cast(desc->option_); + ASSERT_TRUE(opt); + std::string new_value(opt->getValue() + std::string(".") + opt->getValue()); + opt->setValue(new_value); + } +} + +// Macro the make SCOPED_TRACE around equivalance function more compact and helpful. +#define SCOPED_OPT_COMPARE(exp_opt,test_opt)\ +{\ + std::stringstream oss;\ + oss << "Options not equal:\n"\ + << " exp_opt: " << exp_opt.option_->toText() << "\n"\ + << " test_opt: " << (test_opt.option_ ? test_opt.option_->toText() : "") << "\n";\ + SCOPED_TRACE(oss.str());\ + testOptionsEquivalent(exp_opt,test_opt);\ +} + +// Verify that one can add multiple global instances of the same option code +// and that they can be distinguished via their client_classes. +void +GenericConfigBackendDHCPv6Test::globalOption6WithClientClassesTest() { + // Add the options to global scope. + auto ref_options = makeClassTaggedOptions(); + for (auto const& ref_option : ref_options) { + // Add option to the config back end. + cbptr_->createUpdateOption6(ServerSelector::ALL(), ref_option); + } + + // Make sure that we can find each option. + OptionDescriptorPtr found_option; + for (auto const& ref_option : ref_options) { + // Find the option by code and client_classes. + found_option = cbptr_->getOption6(ServerSelector::ALL(), + ref_option->option_->getType(), + DHCP6_OPTION_SPACE, + ref_option->copyClientClasses()); + ASSERT_TRUE(found_option) << "ref_option" << ref_option->option_->toText() + << ", cc: " << ref_option->client_classes_.toText(); + SCOPED_OPT_COMPARE((*ref_option), (*found_option)); + } + + // Update the option values. + updateClassTaggedOptions(ref_options); + + // Update each option in the backend. + for (auto const& ref_option : ref_options) { + // Update option in the config back end. + cbptr_->createUpdateOption6(ServerSelector::ALL(), ref_option); + + // Fetch and verify the updated option. + found_option = cbptr_->getOption6(ServerSelector::ALL(), + ref_option->option_->getType(), + DHCP6_OPTION_SPACE, + ref_option->copyClientClasses()); + ASSERT_TRUE(found_option); + SCOPED_OPT_COMPARE((*ref_option), (*found_option)); + } + + // Delete each option from the backend. + for (auto const& ref_option : ref_options) { + ClientClassesPtr cclasses = ref_option->copyClientClasses(); + + // Delete the option by code and client_classes. + ASSERT_EQ(1, cbptr_->deleteOption6(ServerSelector::ALL(), + ref_option->option_->getType(), + DHCP6_OPTION_SPACE, + cclasses)); + + // Finding the option by code and client_classes should fail. + found_option = cbptr_->getOption6(ServerSelector::ALL(), + ref_option->option_->getType(), + DHCP6_OPTION_SPACE, + cclasses); + ASSERT_FALSE(found_option); + } +} + +void +GenericConfigBackendDHCPv6Test::getAllOptions6WithClientClassesTest() { + // Describes an option to create. + struct OptData { + uint16_t code_; + uint32_t value_; + std::string cclass_; + ServerSelector server_; + }; + + auto server1 = ServerSelector::ONE("server1"); + auto server2 = ServerSelector::ONE("server2"); + auto all = ServerSelector::ALL(); + // List of options to create. + std::list opts_to_make = { + { 231, 1, "cc-1", server1 }, + { 231, 2, "cc-2", server1 }, + { 232, 3, "cc-3", server1 }, + { 232, 4, "cc-3", server2 }, + { 233, 5, "cc-4", server1 }, + { 233, 6, "cc-4", all }, + { 234, 7, "cc-5", all } + }; + + // Create two servers. + ASSERT_NO_THROW_LOG(cbptr_->createUpdateServer6(test_servers_[1])); + ASSERT_NO_THROW_LOG(cbptr_->createUpdateServer6(test_servers_[2])); + + // Add all of the global options. + std::vector ref_options; + for (auto const& opt_to_make : opts_to_make) { + OptionDescriptor desc = createOption>(Option::V6, opt_to_make.code_, + true, false, false, opt_to_make.value_); + desc.space_name_ = DHCP6_OPTION_SPACE; + if (!opt_to_make.cclass_.empty()) { + desc.addClientClass(opt_to_make.cclass_); + } + + ref_options.push_back(OptionDescriptorPtr(new OptionDescriptor(desc))); + ASSERT_NO_THROW_LOG(cbptr_->createUpdateOption6(opt_to_make.server_, ref_options.back())); + } + + // Try to fetch the collection of global options for the server1. + // Build list of options we expect to get back. + std::vector exp_options; + exp_options.push_back(ref_options[0]); + exp_options.push_back(ref_options[1]); + exp_options.push_back(ref_options[2]); + exp_options.push_back(ref_options[4]); + exp_options.push_back(ref_options[6]); + + OptionContainer returned_options; + ASSERT_NO_THROW_LOG(returned_options = cbptr_->getAllOptions6(server1)); + ASSERT_EQ(returned_options.size(), exp_options.size()); + auto exp_option = exp_options.begin(); + for (auto returned_option : returned_options) { + testOptionsEquivalent(*(*exp_option), returned_option); + ++exp_option; + } + + // Try to fetch the collection of global options for the server2. + // Build list of options we expect to get back. + exp_options.clear(); + exp_options.push_back(ref_options[3]); + exp_options.push_back(ref_options[5]); + exp_options.push_back(ref_options[6]); + + ASSERT_NO_THROW_LOG(returned_options = cbptr_->getAllOptions6(server2)); + ASSERT_EQ(returned_options.size(), exp_options.size()); + exp_option = exp_options.begin(); + for (auto returned_option : returned_options) { + testOptionsEquivalent(*(*exp_option), returned_option); + ++exp_option; + } + + // Try to fetch the collection of global options for the server1. + // Build list of options we expect to get back. + exp_options.clear(); + exp_options.push_back(ref_options[5]); + exp_options.push_back(ref_options[6]); + + ASSERT_NO_THROW_LOG(returned_options = cbptr_->getAllOptions6(all)); + ASSERT_EQ(returned_options.size(), exp_options.size()); + exp_option = exp_options.begin(); + for (auto returned_option : returned_options) { + testOptionsEquivalent(*(*exp_option), returned_option); + ++exp_option; + } +} + void GenericConfigBackendDHCPv6Test::createUpdateDeleteSubnetOption6Test() { // Insert new subnet. @@ -3744,7 +3954,8 @@ GenericConfigBackendDHCPv6Test::createUpdateDeleteSubnetOption6Test() { // It should succeed for any server. EXPECT_EQ(1, cbptr_->deleteOption6(ServerSelector::ANY(), subnet->getID(), opt_posix_timezone->option_->getType(), - opt_posix_timezone->space_name_)); + opt_posix_timezone->space_name_, + opt_posix_timezone->copyClientClasses())); returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), subnet->getID()); @@ -4874,3 +5085,301 @@ GenericConfigBackendDHCPv6Test::multipleAuditEntriesTest() { distance--; } } + +// Verify that one can add multiple instances of the same option code +// to a shared-network and that they can be distinguished via their client_classes. +void +GenericConfigBackendDHCPv6Test::sharedNetworkOption6WithClientClassesTest() { + // Make a network with options. + SharedNetwork6Ptr network(new SharedNetwork6("net1")); + auto ref_options = makeClassTaggedOptions(); + for (auto const& ref_option : ref_options) { + network->getCfgOption()->add(*ref_option, ref_option->space_name_); + } + + // Add the network to config back end. + cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(), network); + + // Fetch the network. + SharedNetwork6Ptr returned_network = cbptr_->getSharedNetwork6(ServerSelector::ALL(), + network->getName()); + ASSERT_TRUE(returned_network); + + // Make sure that CfgOption->get() with client_classes finds each ref option. + for (auto const& ref_option : ref_options) { + auto cfg_option = returned_network->getCfgOption()->get(DHCP6_OPTION_SPACE, + ref_option->option_->getType(), + ref_option->client_classes_); + SCOPED_OPT_COMPARE((*ref_option), cfg_option); + } + + // Now make sure that we can set the options individually. + updateClassTaggedOptions(ref_options); + for (auto const& ref_option : ref_options) { + cbptr_->createUpdateOption6(ServerSelector::ALL(), network->getName(), ref_option); + } + + // Re-fetch the network. + returned_network = cbptr_->getSharedNetwork6(ServerSelector::ALL(), network->getName()); + ASSERT_TRUE(returned_network); + + // Make sure that CfgOption->get() with client_classes finds each ref option. + for (auto const& ref_option : ref_options) { + auto cfg_option = returned_network->getCfgOption()->get(DHCP6_OPTION_SPACE, + ref_option->option_->getType(), + ref_option->client_classes_); + SCOPED_OPT_COMPARE((*ref_option), cfg_option); + } + + // Now make sure that we can delete the options individually. + for (auto const& ref_option : ref_options) { + ASSERT_EQ(1, cbptr_->deleteOption6(ServerSelector::ANY(), + network->getName(), + ref_option->option_->getType(), + DHCP6_OPTION_SPACE, + ref_option->copyClientClasses())); + } + + // Re-fetch the network. + returned_network = cbptr_->getSharedNetwork6(ServerSelector::ALL(), network->getName()); + ASSERT_TRUE(returned_network); + + // Make sure that CfgOption is empty + auto cfg_option = returned_network->getCfgOption()->getAll(DHCP6_OPTION_SPACE); + EXPECT_TRUE(cfg_option->empty()); +} + +// Verify that one can add multiple instances of the same option code +// to a subnet and that they can be distinguished via their client_classes. +void +GenericConfigBackendDHCPv6Test::subnetOption6WithClientClassesTest() { + // Make a subnet with options. + Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"), 64, + 30, 40, 50, 60, 1024)); + auto ref_options = makeClassTaggedOptions(); + for (auto const& ref_option : ref_options) { + subnet->getCfgOption()->add(*ref_option, ref_option->space_name_); + } + + // Add the subnet to config back end. + cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet); + + // Fetch the subnet. + Subnet6Ptr returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), subnet->getID()); + ASSERT_TRUE(returned_subnet); + + // Make sure that CfgOption->get() with client_classes finds each ref option. + for (auto const& ref_option : ref_options) { + auto cfg_option = returned_subnet->getCfgOption()->get(DHCP6_OPTION_SPACE, + ref_option->option_->getType(), + ref_option->client_classes_); + SCOPED_OPT_COMPARE((*ref_option), cfg_option); + } + + // Now make sure that we can set the options individually. + updateClassTaggedOptions(ref_options); + for (auto const& ref_option : ref_options) { + cbptr_->createUpdateOption6(ServerSelector::ALL(), subnet->getID(), ref_option); + } + + // Re-fetch the subnet. + returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), subnet->getID()); + ASSERT_TRUE(returned_subnet); + + // Make sure that CfgOption->get() with client_classes finds each ref option. + for (auto const& ref_option : ref_options) { + auto cfg_option = returned_subnet->getCfgOption()->get(DHCP6_OPTION_SPACE, + ref_option->option_->getType(), + ref_option->client_classes_); + SCOPED_OPT_COMPARE((*ref_option), cfg_option); + } + + // Now make sure that we can delete the options individually. + for (auto const& ref_option : ref_options) { + ASSERT_EQ(1, cbptr_->deleteOption6(ServerSelector::ANY(), + subnet->getID(), + ref_option->option_->getType(), + DHCP6_OPTION_SPACE, + ref_option->copyClientClasses())); + } + + // Re-fetch the subnet. + returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), subnet->getID()); + ASSERT_TRUE(returned_subnet); + + // Make sure that CfgOption is empty + auto cfg_option = returned_subnet->getCfgOption()->getAll(DHCP6_OPTION_SPACE); + EXPECT_TRUE(cfg_option->empty()); +} + +// Verify that one can add multiple instances of the same option code +// to a pool and that they can be distinguished via their client_classes. +void +GenericConfigBackendDHCPv6Test::poolOption6WithClientClassesTest() { + // Make subnet with a pool with options. + Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"), 64, + 30, 40, 50, 60, 1024)); + + Pool6Ptr pool(new Pool6(Lease::TYPE_NA, + IOAddress("2001:db8::10"), IOAddress("2001:db8::20"))); + subnet->addPool(pool); + + // Add the options to the pool. + auto ref_options = makeClassTaggedOptions(); + for (auto const& ref_option : ref_options) { + pool->getCfgOption()->add(*ref_option, ref_option->space_name_); + } + + // Add the subnet to config back end. + cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet); + + // Fetch this subnet by subnet identifier. + Subnet6Ptr returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), + subnet->getID()); + ASSERT_TRUE(returned_subnet); + + PoolPtr returned_pool = returned_subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8::10")); + ASSERT_TRUE(returned_pool); + + // Make sure that CfgOption->get() with client_classes finds each ref option. + for (auto const& ref_option : ref_options) { + auto cfg_option = returned_pool->getCfgOption()->get(DHCP6_OPTION_SPACE, + ref_option->option_->getType(), + ref_option->client_classes_); + SCOPED_OPT_COMPARE((*ref_option), cfg_option); + } + + // Now make sure that we can set the options individually. + updateClassTaggedOptions(ref_options); + for (auto const& ref_option : ref_options) { + cbptr_->createUpdateOption6(ServerSelector::ALL(), + pool->getFirstAddress(), + pool->getLastAddress(), + ref_option); + } + + // Re-fetch the subnet. + returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), subnet->getID()); + ASSERT_TRUE(returned_subnet); + + returned_pool = returned_subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8::10")); + ASSERT_TRUE(returned_pool); + + // Make sure that CfgOption->get() with client_classes finds each ref option. + for (auto const& ref_option : ref_options) { + auto cfg_option = returned_pool->getCfgOption()->get(DHCP6_OPTION_SPACE, + ref_option->option_->getType(), + ref_option->client_classes_); + SCOPED_OPT_COMPARE((*ref_option), cfg_option); + } + + // Now make sure that we can delete the options individually. + for (auto const& ref_option : ref_options) { + ASSERT_EQ(1, cbptr_->deleteOption6(ServerSelector::ANY(), + pool->getFirstAddress(), + pool->getLastAddress(), + ref_option->option_->getType(), + DHCP6_OPTION_SPACE, + ref_option->copyClientClasses())); + } + + // Re-fetch the subnet. + returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), subnet->getID()); + ASSERT_TRUE(returned_subnet); + + returned_pool = returned_subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8::10")); + ASSERT_TRUE(returned_pool); + + // Make sure that CfgOption is empty + auto cfg_option = returned_pool->getCfgOption()->getAll(DHCP6_OPTION_SPACE); + EXPECT_TRUE(cfg_option->empty()); +} + +// Verify that one can add multiple instances of the same option code +// to a pd pool and that they can be distinguished via their client_classes. +void +GenericConfigBackendDHCPv6Test::pdPoolOption6WithClientClassesTest() { + // Make subnet with a pool with options. + Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"), 64, + 30, 40, 50, 60, 1024)); + + const PoolPtr pool(new Pool6(Lease::TYPE_PD, + IOAddress("2001:db8:a::"), 48, 64)); + auto pool_len = prefixLengthFromRange(pool->getFirstAddress(), + pool->getLastAddress()); + subnet->addPool(pool); + + // Add the options to the pool. + auto ref_options = makeClassTaggedOptions(); + for (auto const& ref_option : ref_options) { + pool->getCfgOption()->add(*ref_option, ref_option->space_name_); + } + + // Add the subnet to config back end. + cbptr_->createUpdateSubnet6(ServerSelector::ALL(), subnet); + + // Fetch this subnet by subnet identifier. + Subnet6Ptr returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), + subnet->getID()); + ASSERT_TRUE(returned_subnet); + + PoolPtr returned_pool = returned_subnet->getPool(Lease::TYPE_PD, + IOAddress("2001:db8:a::")); + ASSERT_TRUE(returned_pool); + + // Make sure that CfgOption->get() with client_classes finds each ref option. + for (auto const& ref_option : ref_options) { + auto cfg_option = returned_pool->getCfgOption()->get(DHCP6_OPTION_SPACE, + ref_option->option_->getType(), + ref_option->client_classes_); + SCOPED_OPT_COMPARE((*ref_option), cfg_option); + } + + // Now make sure that we can set the options individually. + updateClassTaggedOptions(ref_options); + + for (auto const& ref_option : ref_options) { + cbptr_->createUpdateOption6(ServerSelector::ALL(), + pool->getFirstAddress(), + static_cast(pool_len), + ref_option); + } + + // Re-fetch the subnet. + returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), subnet->getID()); + ASSERT_TRUE(returned_subnet); + + returned_pool = returned_subnet->getPool(Lease::TYPE_PD, + IOAddress("2001:db8:a::")); + ASSERT_TRUE(returned_pool); + + // Make sure that CfgOption->get() with client_classes finds each ref option. + for (auto const& ref_option : ref_options) { + auto cfg_option = returned_pool->getCfgOption()->get(DHCP6_OPTION_SPACE, + ref_option->option_->getType(), + ref_option->client_classes_); + SCOPED_OPT_COMPARE((*ref_option), cfg_option); + } + + // Now make sure that we can delete the options individually. + for (auto const& ref_option : ref_options) { + ASSERT_EQ(1, cbptr_->deleteOption6(ServerSelector::ANY(), + pool->getFirstAddress(), + static_cast(pool_len), + ref_option->option_->getType(), + DHCP6_OPTION_SPACE, + ref_option->copyClientClasses())); + } + + // Re-fetch the subnet. + returned_subnet = cbptr_->getSubnet6(ServerSelector::ALL(), subnet->getID()); + ASSERT_TRUE(returned_subnet); + + returned_pool = returned_subnet->getPool(Lease::TYPE_PD, + IOAddress("2001:db8:a::")); + ASSERT_TRUE(returned_pool); + + // Make sure that CfgOption is empty + auto cfg_option = returned_pool->getCfgOption()->getAll(DHCP6_OPTION_SPACE); + EXPECT_TRUE(cfg_option->empty()); +} diff --git a/src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.h b/src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.h index 6e74b1f8f8..b97d85fa06 100644 --- a/src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.h +++ b/src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.h @@ -315,6 +315,22 @@ public: /// @brief This test verifies that modified global options can be retrieved. void getModifiedOptions6Test(); + /// @brief Creates a list of string options with and without client_class tags. + /// It creates 2 D6O_NEW_TZDB_TIMEZONE options and 2 D6O_NEW_POSIX_TIMEZONE options. + std::list makeClassTaggedOptions(); + + /// @brief Updates the value of each string option in the list. + void updateClassTaggedOptions(std::list& options); + + /// @brief This test verifies that multiple instances of an option can + /// be added to global scope and be distinguished from one another + /// by their client-classes content. + void globalOption6WithClientClassesTest(); + + /// @brief This test verifies that global options with varying client-classes + /// and varying server tags are handled properly. + void getAllOptions6WithClientClassesTest(); + /// @brief This test verifies that subnet level option can be added, updated and /// deleted. void createUpdateDeleteSubnetOption6Test(); @@ -373,6 +389,26 @@ public: /// event and it does not matter). void multipleAuditEntriesTest(); + /// @brief This test verifies that multiple instances of an option can + /// be added to a shared-network and be distinguished from one another + /// by their client-classes content. + void sharedNetworkOption6WithClientClassesTest(); + + /// @brief This test verifies that multiple instances of an option can + /// be added to a subnet and be distinguished from one another + /// by their client-classes content. + void subnetOption6WithClientClassesTest(); + + /// @brief This test verifies that multiple instances of an option can + /// be added to a pool and be distinguished from one another + /// by their client-classes content. + void poolOption6WithClientClassesTest(); + + /// @brief This test verifies that multiple instances of an option can + /// be added to a pd pool and be distinguished from one another + /// by their client-classes content. + void pdPoolOption6WithClientClassesTest(); + /// @brief Holds pointers to subnets used in tests. std::vector test_subnets_; diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc index b1c53ac44e..b3a87228e6 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc +++ b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc @@ -1185,7 +1185,7 @@ uint64_t TestConfigBackendDHCPv4::deleteOption4(const db::ServerSelector& server_selector, const uint16_t code, const std::string& space, - ClientClassesPtr client_classes) { + const ClientClassesPtr client_classes) { auto tag = getServerTag(server_selector); uint64_t erased = 0; for (auto option_it = options_.begin(); option_it != options_.end(); ) { @@ -1207,7 +1207,7 @@ TestConfigBackendDHCPv4::deleteOption4(const db::ServerSelector& server_selector const std::string& shared_network_name, const uint16_t code, const std::string& space, - ClientClassesPtr client_classes) { + const ClientClassesPtr client_classes) { auto& index = shared_networks_.get(); auto network_it = index.find(shared_network_name); @@ -1254,7 +1254,7 @@ TestConfigBackendDHCPv4::deleteOption4(const db::ServerSelector& server_selector const SubnetID& subnet_id, const uint16_t code, const std::string& space, - ClientClassesPtr client_classes) { + const ClientClassesPtr client_classes) { auto& index = subnets_.get(); auto subnet_it = index.find(subnet_id); @@ -1301,7 +1301,7 @@ TestConfigBackendDHCPv4::deleteOption4(const db::ServerSelector& server_selector const asiolink::IOAddress& pool_end_address, const uint16_t code, const std::string& space, - ClientClassesPtr client_classes) { + const ClientClassesPtr client_classes) { auto not_in_selected_servers = false; for (auto const& subnet : subnets_) { // Get the pool: if it is not here we can directly go to the next subnet. diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h index baed8fd8bb..61a1a7d59c 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h +++ b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h @@ -446,7 +446,7 @@ public: virtual uint64_t deleteOption4(const db::ServerSelector& server_selector, const uint16_t code, const std::string& space, - ClientClassesPtr client_classes = ClientClassesPtr()); + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes shared network level option. /// @@ -462,7 +462,7 @@ public: const std::string& shared_network_name, const uint16_t code, const std::string& space, - ClientClassesPtr client_classes = ClientClassesPtr()); + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes subnet level option. /// @@ -477,7 +477,7 @@ public: virtual uint64_t deleteOption4(const db::ServerSelector& server_selector, const SubnetID& subnet_id, const uint16_t code, const std::string& space, - ClientClassesPtr client_classes = ClientClassesPtr()); + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes pool level option. /// @@ -497,7 +497,7 @@ public: const asiolink::IOAddress& pool_end_address, const uint16_t code, const std::string& space, - ClientClassesPtr client_classes = ClientClassesPtr()); + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes global parameter. /// diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.cc b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.cc index ed2451bd03..15d8edbd1d 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.cc +++ b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.cc @@ -370,7 +370,8 @@ TestConfigBackendDHCPv6::getModifiedOptionDefs6(const db::ServerSelector& server OptionDescriptorPtr TestConfigBackendDHCPv6::getOption6(const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space) const { + const std::string& space, + const ClientClassesPtr client_classes) const { auto const& tags = server_selector.getTags(); auto candidate = OptionDescriptorPtr(); auto const& index = options_.get<1>(); @@ -378,11 +379,16 @@ TestConfigBackendDHCPv6::getOption6(const db::ServerSelector& server_selector, BOOST_FOREACH(auto const& option_it, option_it_pair) { if (option_it.space_name_ == space) { + if (client_classes && (option_it.client_classes_ != *client_classes)) { + continue; + } + for (auto const& tag : tags) { if (option_it.hasServerTag(ServerTag(tag))) { return (OptionDescriptorPtr(new OptionDescriptor(option_it))); } } + if (option_it.hasAllServerTag()) { candidate = OptionDescriptorPtr(new OptionDescriptor(option_it)); } @@ -741,6 +747,7 @@ TestConfigBackendDHCPv6::createUpdateOption6(const db::ServerSelector& server_se option_it != option_it_pair.second; ++option_it) { if ((option_it->space_name_ == option->space_name_) && + (option_it->client_classes_ == option->client_classes_) && (option_it->hasServerTag(ServerTag(tag)))) { index.replace(option_it, *option); return; @@ -787,7 +794,8 @@ TestConfigBackendDHCPv6::createUpdateOption6(const db::ServerSelector& server_se << " not present in a selected server"); } - shared_network->getCfgOption()->del(option->space_name_, option->option_->getType()); + shared_network->getCfgOption()->del(option->space_name_, option->option_->getType(), + option->client_classes_); shared_network->getCfgOption()->add(*option, option->space_name_); } @@ -828,7 +836,8 @@ TestConfigBackendDHCPv6::createUpdateOption6(const db::ServerSelector& server_se << " not present in a selected server"); } - subnet->getCfgOption()->del(option->space_name_, option->option_->getType()); + subnet->getCfgOption()->del(option->space_name_, option->option_->getType(), + option->client_classes_); subnet->getCfgOption()->add(*option, option->space_name_); } @@ -868,7 +877,8 @@ TestConfigBackendDHCPv6::createUpdateOption6(const db::ServerSelector& server_se } // Update the option. - pool->getCfgOption()->del(option->space_name_, option->option_->getType()); + pool->getCfgOption()->del(option->space_name_, option->option_->getType(), + option->client_classes_); pool->getCfgOption()->add(*option, option->space_name_); return; @@ -922,7 +932,8 @@ TestConfigBackendDHCPv6::createUpdateOption6(const db::ServerSelector& server_se } // Update the option. - pdpool->getCfgOption()->del(option->space_name_, option->option_->getType()); + pdpool->getCfgOption()->del(option->space_name_, option->option_->getType(), + option->client_classes_); pdpool->getCfgOption()->add(*option, option->space_name_); return; @@ -1228,13 +1239,15 @@ TestConfigBackendDHCPv6::deleteAllOptionDefs6(const db::ServerSelector& server_s uint64_t TestConfigBackendDHCPv6::deleteOption6(const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space) { + const std::string& space, + ClientClassesPtr client_classes) { auto const& tag = getServerTag(server_selector); uint64_t erased = 0; for (auto option_it = options_.begin(); option_it != options_.end(); ) { if ((option_it->option_->getType() == code) && (option_it->space_name_ == space) && - (option_it->hasServerTag(ServerTag(tag)))) { + (option_it->hasServerTag(ServerTag(tag))) && + (!client_classes || (option_it->client_classes_ == *client_classes))) { option_it = options_.erase(option_it); ++erased; } else { @@ -1248,7 +1261,8 @@ uint64_t TestConfigBackendDHCPv6::deleteOption6(const db::ServerSelector& server_selector, const std::string& shared_network_name, const uint16_t code, - const std::string& space) { + const std::string& space, + ClientClassesPtr client_classes) { auto& index = shared_networks_.get(); auto network_it = index.find(shared_network_name); @@ -1276,12 +1290,17 @@ TestConfigBackendDHCPv6::deleteOption6(const db::ServerSelector& server_selector } } } + if (!found) { isc_throw(BadValue, "attempted to delete option in a " "shared network " << shared_network_name << " not present in a selected server"); } + if (client_classes) { + return (shared_network->getCfgOption()->del(space, code, *client_classes)); + } + return (shared_network->getCfgOption()->del(space, code)); } @@ -1289,7 +1308,8 @@ uint64_t TestConfigBackendDHCPv6::deleteOption6(const db::ServerSelector& server_selector, const SubnetID& subnet_id, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { auto& index = subnets_.get(); auto subnet_it = index.find(subnet_id); @@ -1317,12 +1337,17 @@ TestConfigBackendDHCPv6::deleteOption6(const db::ServerSelector& server_selector } } } + if (!found) { isc_throw(BadValue, "attempted to delete option in a " "subnet ID " << subnet_id << " not present in a selected server"); } + if (client_classes) { + return (subnet->getCfgOption()->del(space, code, *client_classes)); + } + return (subnet->getCfgOption()->del(space, code)); } @@ -1331,7 +1356,8 @@ TestConfigBackendDHCPv6::deleteOption6(const db::ServerSelector& server_selector const asiolink::IOAddress& pool_start_address, const asiolink::IOAddress& pool_end_address, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { auto not_in_selected_servers = false; for (auto const& subnet : subnets_) { // Get the pool: if it is not here we can directly go to the next subnet. @@ -1363,6 +1389,10 @@ TestConfigBackendDHCPv6::deleteOption6(const db::ServerSelector& server_selector } } + if (client_classes) { + return (pool->getCfgOption()->del(space, code, *client_classes)); + } + return (pool->getCfgOption()->del(space, code)); } @@ -1381,7 +1411,8 @@ TestConfigBackendDHCPv6::deleteOption6(const db::ServerSelector& server_selector const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space) { + const std::string& space, + const ClientClassesPtr client_classes) { auto not_in_selected_servers = false; for (auto const& subnet : subnets_) { // Get the pd pool: if it is not here we can directly go to the next subnet. @@ -1412,6 +1443,10 @@ TestConfigBackendDHCPv6::deleteOption6(const db::ServerSelector& server_selector } } + if (client_classes) { + return (pdpool->getCfgOption()->del(space, code, *client_classes)); + } + return (pdpool->getCfgOption()->del(space, code)); } diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.h b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.h index 8c65bb20f1..bb247d3c06 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.h +++ b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.h @@ -167,11 +167,16 @@ public: /// @brief Retrieves single option by code and space. /// /// @param server_selector Server selector. + /// @param code Code of the option to be deleted. + /// @param space Option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Pointer to the retrieved option descriptor or null if /// no option was found. virtual OptionDescriptorPtr getOption6(const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space) const; + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()) const; /// @brief Retrieves all global options. /// @@ -448,10 +453,13 @@ public: /// @param server_selector Server selector. /// @param code Code of the option to be deleted. /// @param space Option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes shared network level option. /// @@ -460,11 +468,15 @@ public: /// belongs to. /// @param code Code of the option to be deleted. /// @param space Option space of the option to be deleted. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. + /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const std::string& shared_network_name, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes subnet level option. /// @@ -475,8 +487,11 @@ public: /// @param space Option space of the deleted option. /// @return Number of deleted options. virtual uint64_t - deleteOption6(const db::ServerSelector& server_selector, const SubnetID& subnet_id, - const uint16_t code, const std::string& space); + deleteOption6(const db::ServerSelector& server_selector, + const SubnetID& subnet_id, + const uint16_t code, + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes pool level option. /// @@ -487,13 +502,16 @@ public: /// deleted option belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const asiolink::IOAddress& pool_start_address, const asiolink::IOAddress& pool_end_address, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes pd pool level option. /// @@ -504,13 +522,16 @@ public: /// the deleted option belongs. /// @param code Code of the deleted option. /// @param space Option space of the deleted option. + /// @param client_classes Optional client classes list of the option to be deleted. + /// Defaults to an empty pointer. /// @return Number of deleted options. virtual uint64_t deleteOption6(const db::ServerSelector& server_selector, const asiolink::IOAddress& pd_pool_prefix, const uint8_t pd_pool_prefix_length, const uint16_t code, - const std::string& space); + const std::string& space, + const ClientClassesPtr client_classes = ClientClassesPtr()); /// @brief Deletes global parameter. /// diff --git a/src/share/api/remote-option4-global-del.json b/src/share/api/remote-option4-global-del.json index db2388ab0b..9fe778c5de 100644 --- a/src/share/api/remote-option4-global-del.json +++ b/src/share/api/remote-option4-global-del.json @@ -14,7 +14,7 @@ " \"options\": [", " {", " \"code\":