]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#4014] Core and UT for v6 option class-tags
authorThomas Markwalder <tmark@isc.org>
Mon, 28 Jul 2025 17:48:45 +0000 (13:48 -0400)
committerThomas Markwalder <tmark@isc.org>
Tue, 29 Jul 2025 12:30:06 +0000 (08:30 -0400)
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

38 files changed:
doc/sphinx/arm/hooks-cb-cmds.rst
src/hooks/dhcp/mysql/mysql_cb_dhcp6.cc
src/hooks/dhcp/mysql/mysql_cb_dhcp6.h
src/hooks/dhcp/mysql/mysql_cb_impl.cc
src/hooks/dhcp/mysql/tests/mysql_cb_dhcp6_unittest.cc
src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.cc
src/hooks/dhcp/pgsql/pgsql_cb_dhcp6.h
src/hooks/dhcp/pgsql/pgsql_cb_impl.cc
src/hooks/dhcp/pgsql/tests/pgsql_cb_dhcp6_unittest.cc
src/lib/dhcpsrv/config_backend_dhcp6.h
src/lib/dhcpsrv/config_backend_pool_dhcp6.cc
src/lib/dhcpsrv/config_backend_pool_dhcp6.h
src/lib/dhcpsrv/testutils/generic_cb_dhcp4_unittest.h
src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.cc
src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.h
src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc
src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h
src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.cc
src/lib/dhcpsrv/testutils/test_config_backend_dhcp6.h
src/share/api/remote-option4-global-del.json
src/share/api/remote-option4-global-get.json
src/share/api/remote-option4-global-set.json
src/share/api/remote-option4-network-del.json
src/share/api/remote-option4-network-set.json
src/share/api/remote-option4-pool-del.json
src/share/api/remote-option4-pool-set.json
src/share/api/remote-option4-subnet-del.json
src/share/api/remote-option4-subnet-set.json
src/share/api/remote-option6-global-del.json
src/share/api/remote-option6-global-get.json
src/share/api/remote-option6-global-set.json
src/share/api/remote-option6-network-del.json
src/share/api/remote-option6-network-set.json
src/share/api/remote-option6-pd-pool-del.json
src/share/api/remote-option6-pd-pool-set.json
src/share/api/remote-option6-pool-del.json
src/share/api/remote-option6-pool-set.json
src/share/api/remote-option6-subnet-del.json

index 68c638c324f7426a3bfb0867026aedf45f5a5a60..5084a15af889c9d566be55758ca76da793c16b0c 100644 (file)
@@ -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
index ab96f4faf4b6e9b2d7b420fa27bf61efebdbc842..b5249b23cb0f54f6623829de127e66960ac96265 100644 (file)
@@ -2175,7 +2175,8 @@ public:
             MySqlBinding::createNull(),
             MySqlBinding::createString(tag),
             MySqlBinding::createInteger<uint8_t>(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<uint32_t>(static_cast<uint32_t>(subnet_id)),
             MySqlBinding::createInteger<uint16_t>(option->option_->getType()),
-            MySqlBinding::condCreateString(option->space_name_)
+            MySqlBinding::condCreateString(option->space_name_),
+            createInputClientClassesBinding(option->client_classes_)
         };
 
         boost::scoped_ptr<MySqlTransaction> 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<uint64_t>(pool_id));
         in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(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<uint16_t>(option->option_->getType()),
-            MySqlBinding::condCreateString(option->space_name_)
+            MySqlBinding::condCreateString(option->space_name_),
+            createInputClientClassesBinding(option->client_classes_)
         };
 
         boost::scoped_ptr<MySqlTransaction> 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<uint8_t>(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<uint16_t>(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<uint32_t>(static_cast<uint32_t>(subnet_id)),
             MySqlBinding::createInteger<uint16_t>(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<uint16_t>(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<uint16_t>(code),
             MySqlBinding::createString(space),
+            createClientClassesForWhereClause(client_classes),
             MySqlBinding::createString(pd_pool_prefix.toText()),
             MySqlBinding::createInteger<uint8_t>(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<uint16_t>(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);
index 22b9f615a7824bcba62923a33984c284be4d8f5b..97d068263073bac1d4191b0b2f353defac308ad1 100644 (file)
@@ -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.
     ///
index ebf2d74dc09c912287af5129d73c3ea8e3a79566..4418fccfbf0d1a97fe7d42b50f274ecfb10815e4 100644 (file)
@@ -580,11 +580,8 @@ MySqlConfigBackendImpl::getOption(const int index,
         in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(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()));
index 3580dfa6e7e451ed42b9697153b3bb817f4314b1..7a5bdf6901e3b5e13e8f92f8b34c3daedda3fcc1 100644 (file)
@@ -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 {
index 424d847f4338a950224750b4065c2a4a1fafe91c..3528292a37742aef751c91275077d4c6e80abe14 100644 (file)
@@ -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);
index 056d722bfb151bf14346f3af2e9fe0a793330cd5..44f8c5529acaf8d04a86bac30d0cbba56bbab5ac 100644 (file)
@@ -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.
     ///
index c41995ce74766838c94fe5131256812e33d60806..5e8a0e103d2ab494380d49eea54588157bc10af9 100644 (file)
@@ -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() :
index df80329638516d2e1cbf871ee5ed6a58bf0b0c18..4b5ff7019ee38b1d83b3558c0fcc80af336f1f9b 100644 (file)
@@ -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 {
index 37a7e7f6c858a6f7961bdf49137e2a818208c337..9275585f0a4d0e2e81e1e0e53f90b0ee687af711 100644 (file)
@@ -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.
     ///
index 05513e12cb2e6f0cf5a830dbb26b5d82efaab670..405d59e996ff139ab54162e35311e687bd4f3868 100644 (file)
@@ -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<OptionDescriptorPtr, uint16_t, const std::string&>
         (&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<uint64_t, uint16_t, const std::string&>
+                                       const std::string& space,
+                                       const ClientClassesPtr client_classes
+                                             /* = ClientClassesPtr() */) {
+    return (createUpdateDeleteProperty<uint64_t, uint16_t, const std::string&,
+                                       const ClientClassesPtr>
             (&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<uint64_t, const std::string&, uint16_t,
-                                       const std::string&>
+                                       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<uint64_t, const SubnetID&, uint16_t, const std::string&>
+                                       const std::string& space,
+                                       const ClientClassesPtr client_classes
+                                             /* = ClientClassesPtr() */) {
+    return (createUpdateDeleteProperty<uint64_t, const SubnetID&, uint16_t,
+                                       const std::string&,
+                                       const ClientClassesPtr>
             (&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<uint64_t, const IOAddress&, const IOAddress&,
-                                       uint16_t, const std::string&>
+                                       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<uint64_t, const IOAddress&, uint8_t,
-                                       uint16_t, const std::string&>
+                                       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
index c8660000d81ff8368169bfa196c11716da1f135b..e122beb959a7f1840dc220621197e1488f2af8a5 100644 (file)
@@ -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.
     ///
index 4a89d5cd8953f79c91471bd55604bf1fb40f6c0f..9dc140805166c1ad722d483161c7210adcbed61c 100644 (file)
@@ -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<OptionDescriptorPtr> makeClassTaggedOptions();
 
     /// @brief Updates the value of each string option in the list.
index 726e5f98a751c7136ebb8c2b34335f99cb765042..0056724bf24ca6f087e211b8e977ab7b3770ccfc 100644 (file)
@@ -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<OptionDescriptorPtr>
+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<OptData> 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<OptionDescriptorPtr> tagged_options;
+    for (auto const& opt_to_make : opts_to_make) {
+        OptionDescriptor desc = createOption<OptionString>(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<OptionDescriptorPtr>& options) {
+    for (auto& desc : options) {
+        OptionStringPtr opt = boost::dynamic_pointer_cast<OptionString>(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() : "<null>") << "\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<OptData> 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<OptionDescriptorPtr> ref_options;
+    for (auto const& opt_to_make : opts_to_make) {
+        OptionDescriptor desc = createOption<OptionInt<uint32_t>>(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<OptionDescriptorPtr> 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<uint8_t>(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<uint8_t>(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());
+}
index 6e74b1f8f8d3a3b3910d1e28ab574001ae9594ba..b97d85fa06bcecaf1b25d7c7cea1e91fb0fcc4fe 100644 (file)
@@ -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<OptionDescriptorPtr> makeClassTaggedOptions();
+
+    /// @brief Updates the value of each string option in the list.
+    void updateClassTaggedOptions(std::list<OptionDescriptorPtr>& 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<Subnet6Ptr> test_subnets_;
 
index b1c53ac44e7c06a9182888c95135c19685d2cd31..b3a87228e639e3193f1d7d7fb568c2d7fe4da62c 100644 (file)
@@ -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<SharedNetworkNameIndexTag>();
     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<SubnetSubnetIdIndexTag>();
     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.
index baed8fd8bbb4f546417426fd76a905ccbad998cf..61a1a7d59c50ede89a1217e2e374840a01d765a1 100644 (file)
@@ -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.
     ///
index ed2451bd036bf958bc6256df3976df15158f3fdc..15d8edbd1de9cb3f94021359e31d760871e01781 100644 (file)
@@ -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<SharedNetworkNameIndexTag>();
     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<SubnetSubnetIdIndexTag>();
     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));
     }
 
index 8c65bb20f15dc9795b73bdf9438b9dd611c51a14..bb247d3c062fde062f7e445bba2130f6fce8cfa1 100644 (file)
@@ -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.
     ///
index db2388ab0b6698e30b4544fac5c9d2ad639cd84d..9fe778c5de836c38e3eb13932a052d0ef79872d9 100644 (file)
@@ -14,7 +14,7 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
         "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
index ced2c2ce0bc4c958fb1e1ba03729a15ce745ff66..a2a9a1f43ff9c534674482f1e5a09ee798358005 100644 (file)
@@ -14,7 +14,7 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
         "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
index f103061ea3cfcd20845ba2bdded1d716ecafcbb0..ed0b8da5252f5e178e9d3a2f7ec833cdf27bbe11 100644 (file)
@@ -33,7 +33,7 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
         "                \"client-classes\": [ <one or more comma-separated strings> ]",
         "            }",
         "        ]",
index b60563fe32d9e437f509b3d891afd28818d061cb..04d19d0d1fd71109f72e900e94397f633e23a8e1 100644 (file)
@@ -19,8 +19,8 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
-        "                \"client-classes\": [ <zero or more comma-separated strings> ],",
+        "                \"space\": <option space>,",
+        "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
         "        \"remote\": {",
index 23bf0c8c6dc386948dbe54ddfc753d37d9c09fca..72fa2dee04e4c6cede11800c114df5ecf20347c3 100644 (file)
@@ -37,7 +37,7 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
         "                \"client-classes\": [ <one or more comma-separated strings> ]",
         "            }",
         "        ]",
index 61fd9cc1f2bfce21746c50abcea50cd5fcf3d89d..7fb8c395c80901ab3d9a3fd124cf81fc886f0880 100644 (file)
@@ -19,7 +19,7 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
         "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
index c410a39c6bd96bfbb520a6774bc01ac831f87a58..3a70ad57d6bbad0c760577501acce5601deff97b 100644 (file)
@@ -37,7 +37,7 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
         "                \"client-classes\": [ <one or more comma-separated strings> ]",
         "            }",
         "        ]",
index f8c88719dbe3560a821b469c38a4fdb20c441032..8bc230e0d97ea27fe371c9c93562ce6c3b4eafbe 100644 (file)
@@ -19,7 +19,7 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
         "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
index f6311d93d62bd0af76707d1c4519f64ae25817fe..c79d371c54f62c700b13fbecf306dc544b085d7b 100644 (file)
@@ -37,7 +37,7 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
         "                \"client-classes\": [ <one or more comma-separated strings> ]",
         "            }",
         "        ]",
index e5c3a354fe1f0f24c68afdba2a0a82c78cecc760..ea4dc3e127980e4a8dd45cbe8e3ac68fa99feb90 100644 (file)
@@ -5,7 +5,7 @@
         "This command deletes a DHCPv6 global option from the configuration database."
     ],
     "cmd-comment": [
-        "This command includes a list with exactly one option specification, comprising an option name and code. Specifying an empty list, a value of ``null``, or multiple server tags will result in an error."
+        "This command includes a list with exactly one option specification, comprising an option name, code, and as of Kea 3.1.1, an optional client-classes parameter (see :ref:`cb-cmds-option-class-tags-as-keys`). Specifying an empty list, a value of ``null``, or multiple server tags will result in an error."
     ],
     "cmd-syntax": [
         "{",
@@ -14,7 +14,8 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
+        "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
         "        \"remote\": {",
index 487c3de4ecf564914b53a01dd95618b4021bcb5d..451fa57beb7a599bfa6457b77e303bc19cd437a1 100644 (file)
@@ -5,7 +5,7 @@
         "This command fetches a global DHCPv6 option for the server from the specified database."
     ],
     "cmd-comment": [
-        "The option is identified by the pair of option code/space values. The ``server-tags`` list is mandatory and must contain exactly one server tag. Specifying an empty list, a value of ``null``, or multiple server tags will result in an error. The server tag \"all\" is allowed, to fetch the global option instance shared by all servers."
+        "The option is identified by the pair of option code/space values, and as of Kea 3.1.1, an optional client-classes parameter (see :ref:`cb-cmds-option-class-tags-as-keys`). The ``server-tags`` list is mandatory and must contain exactly one server tag. Specifying an empty list, a value of ``null``, or multiple server tags will result in an error. The server tag \"all\" is allowed, to fetch the global option instance shared by all servers."
     ],
     "cmd-syntax": [
         "{",
@@ -14,7 +14,8 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
+        "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
         "        \"remote\": {",
index 27274038b643bcd8f42db3f3f8b45614ba5f44a8..8dfe0c95f5db43d2fc3aeede69c18554161d7434 100644 (file)
@@ -33,7 +33,8 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
+        "                \"client-classes\": [ <one or more comma-separated strings> ]",
         "            }",
         "        ]",
         "    }",
index 6a819290659cb25ff66e950c295ce1d463d2cdeb..e7a344c4f4b7ff178d807ab037530994febb7f7a 100644 (file)
@@ -5,7 +5,7 @@
         "This command deletes a DHCPv6 option from a shared network from the configuration database."
     ],
     "cmd-comment": [
-        "This command includes two lists with exactly one name of the shared network and exactly one option specification, comprising an option name and code. Specifying an empty list, a value of ``null``, or a server tag will result in an error."
+        "This command includes two lists with exactly one name of the shared network and exactly one option specification, comprising an option name, code, and as of Kea 3.1.1, an optional client-classes parameter (see :ref:`cb-cmds-option-class-tags-as-keys`). Specifying an empty list, a value of ``null``, or a server tag will result in an error."
     ],
     "cmd-syntax": [
         "{",
@@ -19,7 +19,8 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
+        "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
         "        \"remote\": {",
index ab989b3b41cc6f1ae0214b6b7b01451512568bfe..9f0da1a31fb17a18e5b80833e2afac7323e23398 100644 (file)
@@ -37,7 +37,8 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
+        "                \"client-classes\": [ <one or more comma-separated strings> ]",
         "            }",
         "        ]",
         "    }",
index f0d2be1441b34a62b4bb62e32573a78efa1177fc..dedc79c47589248b2d8f85966ab2aeb80be5031f 100644 (file)
@@ -5,7 +5,7 @@
         "This command deletes a DHCPv6 option from a prefix delegation pool from the configuration database."
     ],
     "cmd-comment": [
-        "This command includes two lists with exactly one prefix delegation pool specification and exactly one option specification, comprising an option name and code. Specifying an empty list, a value of ``null``, or a server tag will result in an error."
+        "This command includes two lists with exactly one prefix delegation pool specification and exactly one option specification, comprising an option name, code, and as of Kea 3.1.1, an optional client-classes parameter (see :ref:`cb-cmds-option-class-tags-as-keys`). Specifying an empty list, a value of ``null``, or a server tag will result in an error."
     ],
     "cmd-syntax": [
         "{",
@@ -14,7 +14,8 @@
         "        \"pd-pools\": [",
         "            {",
         "                \"prefix\": <pool prefix (address part)>,",
-        "                \"prefix-len\": <pool prefix (length part)>",
+        "                \"prefix-len\": <pool prefix (length part)>,",
+        "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
         "        \"options\": [",
index 17d752e5182c78bd33ca36ca411907be8e249fda..17491d19ac53c1ff03a0f0d176eea8ec78cb855e 100644 (file)
@@ -38,7 +38,8 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
+        "                \"client-classes\": [ <one or more comma-separated strings> ]",
         "            }",
         "        ]",
         "    }",
index 1fafd833c90e37449537e0a7e32d0070cad62639..e4e2be1ae111311f8c870d397eb141ec338de56b 100644 (file)
@@ -5,7 +5,7 @@
         "This command deletes a DHCPv6 option from an address pool from the configuration database."
     ],
     "cmd-comment": [
-        "This command includes two lists with exactly one address pool specification and exactly one option specification, comprising an option name and code. Specifying an empty list, a value of ``null``, or a server tag will result in an error."
+        "This command includes two lists with exactly one address pool specification and exactly one option specification, comprising an option name, code, and as of Kea 3.1.1, an optional client-classes parameter (see :ref:`cb-cmds-option-class-tags-as-keys`). Specifying an empty list, a value of ``null``, or a server tag will result in an error."
     ],
     "cmd-syntax": [
         "{",
@@ -19,7 +19,8 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
+        "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
         "        \"remote\": {",
index ae45e3e49c633f69947067e2d68613f932294b36..e26fd2f2c3be4bc127f53097f963a29ecc52137a 100644 (file)
@@ -37,7 +37,8 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
+        "                \"client-classes\": [ <one or more comma-separated strings> ]",
         "            }",
         "        ]",
         "    }",
index ff24ed3482a79436d18b1ca556760c1afd92cbfa..7eb69dffe49bb3ed0011054852349113fd1dcd0f 100644 (file)
@@ -5,7 +5,7 @@
         "This command deletes a DHCPv6 option from a subnet from the configuration database."
     ],
     "cmd-comment": [
-        "This command includes two lists with exactly one ID of the subnet and exactly one option specification, comprising an option name and code. Specifying an empty list, a value of ``null``, or a server tag will result in an error."
+        "This command includes two lists with exactly one ID of the subnet and exactly one option specification, comprising an option name, code, and as of Kea 3.1.1, an optional client-classes parameter (see :ref:`cb-cmds-option-class-tags-as-keys`). Specifying an empty list, a value of ``null``, or a server tag will result in an error."
     ],
     "cmd-syntax": [
         "{",
@@ -19,7 +19,8 @@
         "        \"options\": [",
         "            {",
         "                \"code\": <option code>,",
-        "                \"space\": <option space>",
+        "                \"space\": <option space>,",
+        "                \"client-classes\": [ <zero or more comma-separated strings> ]",
         "            }",
         "        ],",
         "        \"remote\": {",