]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3583] MySQL CB V4 supports option class tagging
authorThomas Markwalder <tmark@isc.org>
Tue, 1 Oct 2024 15:31:28 +0000 (11:31 -0400)
committerThomas Markwalder <tmark@isc.org>
Tue, 15 Oct 2024 17:51:57 +0000 (13:51 -0400)
/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc
/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc
/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h
/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h
/src/lib/config_backend/constants.h
/src/lib/dhcpsrv/testutils/generic_cb_dhcp4_unittest.cc

src/hooks/dhcp/mysql/mysql_cb_dhcp4.cc
src/hooks/dhcp/mysql/mysql_cb_impl.cc
src/hooks/dhcp/mysql/mysql_cb_impl.h
src/hooks/dhcp/mysql/mysql_query_macros_dhcp.h
src/lib/config_backend/constants.h
src/lib/dhcpsrv/testutils/generic_cb_dhcp4_unittest.cc

index 3ab91e1d318ef60e401df2712667b45a123d5c17..27bc8fbc0f4f68f1cd07bd3d10e780b0cfbfe624 100644 (file)
@@ -324,6 +324,7 @@ public:
             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pool option: shared_network_name
             MySqlBinding::createInteger<uint64_t>(), // pool option: pool_id
             MySqlBinding::createTimestamp(), //pool option: modification_ts
+            MySqlBinding::createString(OPTION_CLIENT_CLASSES_BUF_LENGTH), // pool option: client_classes
             MySqlBinding::createInteger<uint64_t>(), // option: option_id
             MySqlBinding::createInteger<uint8_t>(), // option: code
             MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // option: value
@@ -337,6 +338,7 @@ public:
             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name
             MySqlBinding::createInteger<uint64_t>(), // option: pool_id
             MySqlBinding::createTimestamp(), //option: modification_ts
+            MySqlBinding::createString(OPTION_CLIENT_CLASSES_BUF_LENGTH), // option: client_classes
             MySqlBinding::createInteger<uint8_t>(), // calculate_tee_times
             MySqlBinding::createInteger<float>(), // t1_percent
             MySqlBinding::createInteger<float>(), // t2_percent
@@ -411,8 +413,8 @@ public:
                 // min_valid_lifetime at 55.
                 // max_valid_lifetime at 56.
                 auto valid_lifetime = createTriplet(out_bindings[19],
-                                                    out_bindings[55],
-                                                    out_bindings[56]);
+                                                    out_bindings[57],
+                                                    out_bindings[58]);
 
                 // Create subnet with basic settings.
                 last_subnet = Subnet4::create(prefix_pair.first, prefix_pair.second,
@@ -536,97 +538,97 @@ public:
 
                 // valid_lifetime at 19.
 
-                // pool and option from 20 to 50.
+                // pool and option from 20 to 52.
 
-                // calculate_tee_times at 51.
-                if (!out_bindings[51]->amNull()) {
-                    last_subnet->setCalculateTeeTimes(out_bindings[51]->getBool());
+                // calculate_tee_times at 53.
+                if (!out_bindings[53]->amNull()) {
+                    last_subnet->setCalculateTeeTimes(out_bindings[53]->getBool());
                 }
 
-                // t1_percent at 52.
-                if (!out_bindings[52]->amNull()) {
-                    last_subnet->setT1Percent(out_bindings[52]->getFloat());
+                // t1_percent at 54.
+                if (!out_bindings[54]->amNull()) {
+                    last_subnet->setT1Percent(out_bindings[54]->getFloat());
                 }
 
-                // t2_percent at 53.
-                if (!out_bindings[53]->amNull()) {
-                    last_subnet->setT2Percent(out_bindings[53]->getFloat());
+                // t2_percent at 55.
+                if (!out_bindings[55]->amNull()) {
+                    last_subnet->setT2Percent(out_bindings[55]->getFloat());
                 }
 
-                // authoritative at 54.
-                if (!out_bindings[54]->amNull()) {
-                    last_subnet->setAuthoritative(out_bindings[54]->getBool());
+                // authoritative at 56.
+                if (!out_bindings[56]->amNull()) {
+                    last_subnet->setAuthoritative(out_bindings[56]->getBool());
                 }
 
-                // min_valid_lifetime at 55.
-                // max_valid_lifetime at 56.
+                // min_valid_lifetime at 57.
+                // max_valid_lifetime at 58.
 
                 // pool client_class, require_client_classes and user_context
-                // from 57 to 59.
-
-                // ddns_send_updates at 60.
-                if (!out_bindings[60]->amNull()) {
-                    last_subnet->setDdnsSendUpdates(out_bindings[60]->getBool());
-                }
-
-                // ddns_override_no_update at 61.
-                if (!out_bindings[61]->amNull()) {
-                    last_subnet->setDdnsOverrideNoUpdate(out_bindings[61]->getBool());
-                }
+                // from 59 to 61.
 
-                // ddns_override_client_update at 62.
+                // ddns_send_updates at 62.
                 if (!out_bindings[62]->amNull()) {
-                    last_subnet->setDdnsOverrideClientUpdate(out_bindings[62]->getBool());
+                    last_subnet->setDdnsSendUpdates(out_bindings[62]->getBool());
                 }
 
-                // ddns_replace_client_name at 63.
+                // ddns_override_no_update at 63.
                 if (!out_bindings[63]->amNull()) {
-                    last_subnet->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode>
-                        (out_bindings[63]->getInteger<uint8_t>()));
+                    last_subnet->setDdnsOverrideNoUpdate(out_bindings[63]->getBool());
                 }
 
-                // ddns_generated_prefix at 64.
+                // ddns_override_client_update at 64.
                 if (!out_bindings[64]->amNull()) {
-                    last_subnet->setDdnsGeneratedPrefix(out_bindings[64]->getString());
+                    last_subnet->setDdnsOverrideClientUpdate(out_bindings[64]->getBool());
                 }
 
-                // ddns_qualifying_suffix at 65.
+                // ddns_replace_client_name at 65.
                 if (!out_bindings[65]->amNull()) {
-                    last_subnet->setDdnsQualifyingSuffix(out_bindings[65]->getString());
+                    last_subnet->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode>
+                        (out_bindings[65]->getInteger<uint8_t>()));
                 }
 
-                // reservations_in_subnet at 66.
+                // ddns_generated_prefix at 66.
                 if (!out_bindings[66]->amNull()) {
-                    last_subnet->setReservationsInSubnet(out_bindings[66]->getBool());
+                    last_subnet->setDdnsGeneratedPrefix(out_bindings[66]->getString());
                 }
 
-                // reservations_out_of_pool at 67.
+                // ddns_qualifying_suffix at 67.
                 if (!out_bindings[67]->amNull()) {
-                    last_subnet->setReservationsOutOfPool(out_bindings[67]->getBool());
+                    last_subnet->setDdnsQualifyingSuffix(out_bindings[67]->getString());
                 }
 
-                // cache_threshold at 68.
+                // reservations_in_subnet at 68.
                 if (!out_bindings[68]->amNull()) {
-                    last_subnet->setCacheThreshold(out_bindings[68]->getFloat());
+                    last_subnet->setReservationsInSubnet(out_bindings[68]->getBool());
                 }
 
-                // cache_max_age at 69.
+                // reservations_out_of_pool at 69.
                 if (!out_bindings[69]->amNull()) {
-                    last_subnet->setCacheMaxAge(out_bindings[69]->getInteger<uint32_t>());
+                    last_subnet->setReservationsOutOfPool(out_bindings[69]->getBool());
                 }
 
-                // offer lifetime at 70.
+                // cache_threshold at 70.
                 if (!out_bindings[70]->amNull()) {
-                    Optional<uint32_t> offer_lft(out_bindings[70]->getInteger<uint32_t>());
-                    last_subnet->setOfferLft(offer_lft);
+                    last_subnet->setCacheThreshold(out_bindings[70]->getFloat());
                 }
 
-                // allocator at 71.
+                // cache_max_age at 71.
                 if (!out_bindings[71]->amNull()) {
-                    last_subnet->setAllocatorType(out_bindings[71]->getString());
+                    last_subnet->setCacheMaxAge(out_bindings[71]->getInteger<uint32_t>());
                 }
 
-                // server_tag at 72.
+                // offer lifetime at 72.
+                if (!out_bindings[72]->amNull()) {
+                    Optional<uint32_t> offer_lft(out_bindings[72]->getInteger<uint32_t>());
+                    last_subnet->setOfferLft(offer_lft);
+                }
+
+                // allocator at 73.
+                if (!out_bindings[73]->amNull()) {
+                    last_subnet->setAllocatorType(out_bindings[73]->getString());
+                }
+
+                // server_tag at 74.
 
                 // Subnet ready. Add it to the list.
                 auto ret = subnets.insert(last_subnet);
@@ -639,10 +641,10 @@ public:
                 }
             }
 
-            // Check for new server tags at 71.
-            if (!out_bindings[72]->amNull() &&
-                (last_tag != out_bindings[72]->getString())) {
-                last_tag = out_bindings[72]->getString();
+            // Check for new server tags at 74.
+            if (!out_bindings[74]->amNull() &&
+                (last_tag != out_bindings[74]->getString())) {
+                last_tag = out_bindings[74]->getString();
                 if (!last_tag.empty() && !last_subnet->hasServerTag(ServerTag(last_tag))) {
                     last_subnet->setServerTag(last_tag);
                 }
@@ -664,17 +666,17 @@ public:
                 last_pool = Pool4::create(IOAddress(out_bindings[21]->getInteger<uint32_t>()),
                                           IOAddress(out_bindings[22]->getInteger<uint32_t>()));
 
-                // pool client_class at 57.
-                if (!out_bindings[57]->amNull()) {
-                    last_pool->allowClientClass(out_bindings[57]->getString());
+                // pool client_class at 59.
+                if (!out_bindings[59]->amNull()) {
+                    last_pool->allowClientClass(out_bindings[59]->getString());
                 }
 
-                // pool require_client_classes at 58.
-                ElementPtr require_element = out_bindings[58]->getJSON();
+                // pool require_client_classes at 60.
+                ElementPtr require_element = out_bindings[60]->getJSON();
                 if (require_element) {
                     if (require_element->getType() != Element::list) {
                         isc_throw(BadValue, "invalid pool require_client_classes value "
-                                  << out_bindings[58]->getString());
+                                  << out_bindings[60]->getString());
                     }
                     for (auto i = 0; i < require_element->size(); ++i) {
                         auto require_item = require_element->get(i);
@@ -686,8 +688,8 @@ public:
                     }
                 }
 
-                // pool user_context at 59.
-                ElementPtr user_context = out_bindings[59]->getJSON();
+                // pool user_context at 61.
+                ElementPtr user_context = out_bindings[61]->getJSON();
                 if (user_context) {
                     last_pool->setContext(user_context);
                 }
@@ -695,7 +697,7 @@ public:
                 last_subnet->addPool(last_pool);
             }
 
-            // Parse pool-specific option from 25 to 37.
+            // Parse pool-specific option from 25 to 38.
             if (last_pool && !out_bindings[25]->amNull() &&
                 (last_pool_option_id < out_bindings[25]->getInteger<uint64_t>())) {
                 last_pool_option_id = out_bindings[25]->getInteger<uint64_t>();
@@ -706,12 +708,12 @@ public:
                 }
             }
 
-            // Parse subnet-specific option from 38 to 50.
-            if (!out_bindings[38]->amNull() &&
-                (last_option_id < out_bindings[38]->getInteger<uint64_t>())) {
-                last_option_id = out_bindings[38]->getInteger<uint64_t>();
+            // Parse subnet-specific option from 39 to 52.
+            if (!out_bindings[39]->amNull() &&
+                (last_option_id < out_bindings[39]->getInteger<uint64_t>())) {
+                last_option_id = out_bindings[39]->getInteger<uint64_t>();
 
-                OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 38);
+                OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 39);
                 if (desc) {
                     last_subnet->getCfgOption()->add(*desc, desc->space_name_);
                 }
@@ -882,6 +884,7 @@ public:
             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pool option: shared_network_name
             MySqlBinding::createInteger<uint64_t>(), // pool option: pool_id
             MySqlBinding::createTimestamp(), //pool option: modification_ts
+            MySqlBinding::createString(OPTION_CLIENT_CLASSES_BUF_LENGTH) // pool option: client_classes
         };
 
         uint64_t last_pool_id = 0;
@@ -942,7 +945,6 @@ public:
             if (last_pool && !out_bindings[8]->amNull() &&
                 (last_pool_option_id < out_bindings[8]->getInteger<uint64_t>())) {
                 last_pool_option_id = out_bindings[8]->getInteger<uint64_t>();
-
                 OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 8);
                 if (desc) {
                     last_pool->getCfgOption()->add(*desc, desc->space_name_);
@@ -1346,6 +1348,7 @@ public:
             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name
             MySqlBinding::createInteger<uint64_t>(), // option: pool_id
             MySqlBinding::createTimestamp(), // option: modification_ts
+            MySqlBinding::createString(OPTION_CLIENT_CLASSES_BUF_LENGTH), // option: client_classes
             MySqlBinding::createInteger<uint8_t>(), // calculate_tee_times
             MySqlBinding::createInteger<float>(), // t1_percent
             MySqlBinding::createInteger<float>(), // t2_percent
@@ -1472,117 +1475,117 @@ public:
                 }
 
                 // valid_lifetime at 12.
-                // min_valid_lifetime at 33.
-                // max_valid_lifetime at 34.
+                // min_valid_lifetime at 34.
+                // max_valid_lifetime at 35.
                 if (!out_bindings[12]->amNull()) {
                     last_network->setValid(createTriplet(out_bindings[12],
-                                                         out_bindings[33],
-                                                         out_bindings[34]));
+                                                         out_bindings[34],
+                                                         out_bindings[35]));
                 }
 
-                // option from 13 to 25.
+                // option from 13 to 26.
 
-                // calculate_tee_times at 26.
-                if (!out_bindings[26]->amNull()) {
-                    last_network->setCalculateTeeTimes(out_bindings[26]->getBool());
-                }
-
-                // t1_percent at 27.
+                // calculate_tee_times at 27.
                 if (!out_bindings[27]->amNull()) {
-                    last_network->setT1Percent(out_bindings[27]->getFloat());
+                    last_network->setCalculateTeeTimes(out_bindings[27]->getBool());
                 }
 
-                // t2_percent at 28.
+                // t1_percent at 28.
                 if (!out_bindings[28]->amNull()) {
-                    last_network->setT2Percent(out_bindings[28]->getFloat());
+                    last_network->setT1Percent(out_bindings[28]->getFloat());
                 }
 
-                // authoritative at 29.
+                // t2_percent at 29.
                 if (!out_bindings[29]->amNull()) {
-                    last_network->setAuthoritative(out_bindings[29]->getBool());
+                    last_network->setT2Percent(out_bindings[29]->getFloat());
                 }
 
-                // boot_file_name at 30.
+                // authoritative at 30.
                 if (!out_bindings[30]->amNull()) {
-                    last_network->setFilename(out_bindings[30]->getString());
+                    last_network->setAuthoritative(out_bindings[30]->getBool());
                 }
 
-                // next_server at 31.
+                // boot_file_name at 31.
                 if (!out_bindings[31]->amNull()) {
-                    last_network->setSiaddr(IOAddress(out_bindings[31]->getInteger<uint32_t>()));
+                    last_network->setFilename(out_bindings[31]->getString());
                 }
 
-                // server_hostname at 32.
+                // next_server at 32.
                 if (!out_bindings[32]->amNull()) {
-                    last_network->setSname(out_bindings[32]->getString());
+                    last_network->setSiaddr(IOAddress(out_bindings[32]->getInteger<uint32_t>()));
                 }
 
-                // min_valid_lifetime at 33.
-                // max_valid_lifetime at 34.
-
-                // ddns_send_updates at 35.
-                if (!out_bindings[35]->amNull()) {
-                    last_network->setDdnsSendUpdates(out_bindings[35]->getBool());
+                // server_hostname at 33.
+                if (!out_bindings[33]->amNull()) {
+                    last_network->setSname(out_bindings[33]->getString());
                 }
 
-                // ddns_override_no_update at 36.
+                // min_valid_lifetime at 34.
+                // max_valid_lifetime at 35.
+
+                // ddns_send_updates at 36.
                 if (!out_bindings[36]->amNull()) {
-                    last_network->setDdnsOverrideNoUpdate(out_bindings[36]->getBool());
+                    last_network->setDdnsSendUpdates(out_bindings[36]->getBool());
                 }
 
-                // ddns_override_client_update at 37.
+                // ddns_override_no_update at 37.
                 if (!out_bindings[37]->amNull()) {
-                    last_network->setDdnsOverrideClientUpdate(out_bindings[37]->getBool());
+                    last_network->setDdnsOverrideNoUpdate(out_bindings[37]->getBool());
                 }
 
-                // ddns_replace_client_name at 38.
+                // ddns_override_client_update at 38.
                 if (!out_bindings[38]->amNull()) {
-                    last_network->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode>
-                        (out_bindings[38]->getInteger<uint8_t>()));
+                    last_network->setDdnsOverrideClientUpdate(out_bindings[38]->getBool());
                 }
 
-                // ddns_generated_prefix at 39.
+                // ddns_replace_client_name at 39.
                 if (!out_bindings[39]->amNull()) {
-                    last_network->setDdnsGeneratedPrefix(out_bindings[39]->getString());
+                    last_network->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode>
+                        (out_bindings[39]->getInteger<uint8_t>()));
                 }
 
-                // ddns_qualifying_suffix at 40.
+                // ddns_generated_prefix at 40.
                 if (!out_bindings[40]->amNull()) {
-                    last_network->setDdnsQualifyingSuffix(out_bindings[40]->getString());
+                    last_network->setDdnsGeneratedPrefix(out_bindings[40]->getString());
                 }
 
-                // reservations_in_subnet at 41.
+                // ddns_qualifying_suffix at 41.
                 if (!out_bindings[41]->amNull()) {
-                    last_network->setReservationsInSubnet(out_bindings[41]->getBool());
+                    last_network->setDdnsQualifyingSuffix(out_bindings[41]->getString());
                 }
 
                 // reservations_in_subnet at 42.
                 if (!out_bindings[42]->amNull()) {
-                    last_network->setReservationsOutOfPool(out_bindings[42]->getBool());
+                    last_network->setReservationsInSubnet(out_bindings[42]->getBool());
                 }
 
-                // cache_threshold at 43.
+                // reservations_in_subnet at 43.
                 if (!out_bindings[43]->amNull()) {
-                    last_network->setCacheThreshold(out_bindings[43]->getFloat());
+                    last_network->setReservationsOutOfPool(out_bindings[43]->getBool());
                 }
 
-                // cache_max_age at 44.
+                // cache_threshold at 44.
                 if (!out_bindings[44]->amNull()) {
-                    last_network->setCacheMaxAge(out_bindings[44]->getInteger<uint32_t>());
+                    last_network->setCacheThreshold(out_bindings[44]->getFloat());
                 }
 
-                // offer lifetime at 45.
+                // cache_max_age at 45.
                 if (!out_bindings[45]->amNull()) {
-                    Optional<uint32_t> offer_lft(out_bindings[45]->getInteger<uint32_t>());
-                    last_network->setOfferLft(offer_lft);
+                    last_network->setCacheMaxAge(out_bindings[45]->getInteger<uint32_t>());
                 }
 
-                // allocator at 46.
+                // offer lifetime at 46.
                 if (!out_bindings[46]->amNull()) {
-                    last_network->setAllocatorType(out_bindings[46]->getString());
+                    Optional<uint32_t> offer_lft(out_bindings[46]->getInteger<uint32_t>());
+                    last_network->setOfferLft(offer_lft);
+                }
+
+                // allocator at 47.
+                if (!out_bindings[47]->amNull()) {
+                    last_network->setAllocatorType(out_bindings[47]->getString());
                 }
 
-                // server_tag at 47.
+                // server_tag at 48.
 
                 // Add the shared network.
                 auto ret = shared_networks.push_back(last_network);
@@ -1596,15 +1599,15 @@ public:
             }
 
             // Check for new server tags.
-            if (!out_bindings[47]->amNull() &&
-                (last_tag != out_bindings[47]->getString())) {
-                last_tag = out_bindings[47]->getString();
+            if (!out_bindings[48]->amNull() &&
+                (last_tag != out_bindings[48]->getString())) {
+                last_tag = out_bindings[48]->getString();
                 if (!last_tag.empty() && !last_network->hasServerTag(ServerTag(last_tag))) {
                     last_network->setServerTag(last_tag);
                 }
             }
 
-            // Parse option from 13 to 25.
+            // Parse option from 13 to 26.
             if (!out_bindings[13]->amNull() &&
                 (last_option_id < out_bindings[13]->getInteger<uint64_t>())) {
                 last_option_id = out_bindings[13]->getInteger<uint64_t>();
@@ -1848,6 +1851,8 @@ public:
 
         auto tag = getServerTag(server_selector, "creating or updating global option");
 
+        db::MySqlBindingPtr cc_binding = createInputClientClassesBinding(option->client_classes_);
+
         MySqlBindingCollection in_bindings = {
             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
             createOptionValueBinding(option),
@@ -1862,9 +1867,10 @@ public:
             MySqlBinding::createNull(),
             MySqlBinding::createNull(),
             MySqlBinding::createTimestamp(option->getModificationTime()),
+            cc_binding,
             MySqlBinding::createString(tag),
             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
-            MySqlBinding::condCreateString(option->space_name_)
+            MySqlBinding::condCreateString(option->space_name_),
         };
 
         MySqlTransaction transaction(conn_);
@@ -1902,6 +1908,8 @@ public:
                       " (unassigned) is unsupported at the moment");
         }
 
+        db::MySqlBindingPtr cc_binding = createInputClientClassesBinding(option->client_classes_);
+
         MySqlBindingCollection in_bindings = {
             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
             createOptionValueBinding(option),
@@ -1916,6 +1924,7 @@ public:
             MySqlBinding::createNull(),
             MySqlBinding::createNull(),
             MySqlBinding::createTimestamp(option->getModificationTime()),
+            cc_binding,
             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)),
             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
             MySqlBinding::condCreateString(option->space_name_)
@@ -1987,6 +1996,8 @@ public:
                       " (unassigned) is unsupported at the moment");
         }
 
+        db::MySqlBindingPtr cc_binding = createInputClientClassesBinding(option->client_classes_);
+
         MySqlBindingCollection in_bindings = {
             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
             createOptionValueBinding(option),
@@ -2001,6 +2012,7 @@ public:
             MySqlBinding::createNull(),
             MySqlBinding::createInteger<uint64_t>(pool_id),
             MySqlBinding::createTimestamp(option->getModificationTime()),
+            cc_binding,
             MySqlBinding::createInteger<uint64_t>(pool_id),
             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
             MySqlBinding::condCreateString(option->space_name_)
@@ -2043,6 +2055,8 @@ public:
                       " (unassigned) is unsupported at the moment");
         }
 
+        db::MySqlBindingPtr cc_binding = createInputClientClassesBinding(option->client_classes_);
+
         MySqlBindingCollection in_bindings = {
             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
             createOptionValueBinding(option),
@@ -2057,9 +2071,10 @@ public:
             MySqlBinding::createString(shared_network_name),
             MySqlBinding::createNull(),
             MySqlBinding::createTimestamp(option->getModificationTime()),
+            cc_binding,
             MySqlBinding::createString(shared_network_name),
             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
-            MySqlBinding::condCreateString(option->space_name_)
+            MySqlBinding::condCreateString(option->space_name_),
         };
 
         boost::scoped_ptr<MySqlTransaction> transaction;
@@ -2104,6 +2119,8 @@ public:
                       " (unassigned) is unsupported at the moment");
         }
 
+        db::MySqlBindingPtr cc_binding = createInputClientClassesBinding(option->client_classes_);
+
         MySqlBindingCollection in_bindings = {
             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
             createOptionValueBinding(option),
@@ -2118,6 +2135,7 @@ public:
             MySqlBinding::createNull(),
             MySqlBinding::createNull(),
             MySqlBinding::createTimestamp(option->getModificationTime()),
+            cc_binding,
             MySqlBinding::createString(client_class->getName()),
             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
             MySqlBinding::condCreateString(option->space_name_)
@@ -2431,6 +2449,7 @@ public:
             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name
             MySqlBinding::createInteger<uint64_t>(), // option: pool_id
             MySqlBinding::createTimestamp(), // option: modification_ts
+            MySqlBinding::createString(OPTION_CLIENT_CLASSES_BUF_LENGTH), // option: client_classes
             MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server tag
         };
 
@@ -2516,9 +2535,9 @@ public:
             }
 
             // server tag
-            if (!out_bindings[38]->amNull() &&
-                (last_tag != out_bindings[38]->getString())) {
-                last_tag = out_bindings[38]->getString();
+            if (!out_bindings[39]->amNull() &&
+                (last_tag != out_bindings[39]->getString())) {
+                last_tag = out_bindings[39]->getString();
                 if (!last_tag.empty() && !last_client_class->hasServerTag(ServerTag(last_tag))) {
                     last_client_class->setServerTag(last_tag);
                 }
@@ -2535,7 +2554,7 @@ public:
                 }
             }
 
-            // Parse client class specific option from 25 to 37.
+            // Parse client class specific option from 25 to 38.
             if (!out_bindings[25]->amNull() &&
                 (last_option_id < out_bindings[25]->getInteger<uint64_t>())) {
                 last_option_id = out_bindings[25]->getInteger<uint64_t>();
index 4e1475b3636dd88f98d3d0e78794935d58adcd2c..1fdbbfd0029c6a49cca3d9377a57a24ee0ea5605 100644 (file)
@@ -757,6 +757,8 @@ MySqlConfigBackendImpl::getOptions(const int index,
     out_bindings.push_back(MySqlBinding::createInteger<uint64_t>());
     // modification_ts
     out_bindings.push_back(MySqlBinding::createTimestamp());
+    // client_classes
+    out_bindings.push_back(MySqlBinding::createString(OPTION_CLIENT_CLASSES_BUF_LENGTH));
     // server_tag
     out_bindings.push_back(MySqlBinding::createString(SERVER_TAG_BUF_LENGTH));
     // pd_pool_id
@@ -780,7 +782,7 @@ MySqlConfigBackendImpl::getOptions(const int index,
             OptionDescriptorPtr desc = processOptionRow(universe, out_bindings.begin());
             if (desc) {
                 // server_tag for the global option
-                ServerTag last_option_server_tag(out_bindings[13]->getString());
+                ServerTag last_option_server_tag(out_bindings[14]->getString());
                 desc->setServerTag(last_option_server_tag.get());
 
                 // If we're fetching options for a given server (explicit server
@@ -874,6 +876,30 @@ MySqlConfigBackendImpl::processOptionRow(const Option::Universe& universe,
         desc->setId((*first_binding)->getInteger<uint64_t>());
     }
 
+    // user_context at 9.
+    ElementPtr user_context = (*(first_binding + 9))->getJSON();
+    if (user_context) {
+        desc->setContext(user_context);
+    }
+
+    // Get client classes list
+    ElementPtr client_classes = (*(first_binding + 13))->getJSON();
+    if (client_classes) {
+        if (client_classes->getType() != Element::list) {
+            isc_throw(BadValue, "invalid client_classes value "
+                                << (*(first_binding + 13))->getString());
+        }
+
+        for (auto i = 0; i < client_classes->size(); ++i) {
+            auto cclass = client_classes->get(i);
+                if (cclass->getType() != Element::string) {
+                    isc_throw(BadValue, "elements of client_classes list must be valid strings");
+                }
+
+            desc->addClientClass(cclass->stringValue());
+        }
+    }
+
     return (desc);
 }
 
index 24de344f5f82e5ce0556304b9adf92b0a1737d2b..19e88f110d524a66983c640527125f04257b3ac4 100644 (file)
@@ -643,6 +643,25 @@ public:
                 db::MySqlBinding::createNull());
     }
 
+    /// @brief Creates input binding from a list of client classes
+    ///
+    /// @param client_classes ClientClasses collection containing the class names
+    /// @return Pointer to the binding (possibly null binding if there are no
+    /// classes specified).
+    db::MySqlBindingPtr createInputClientClassesBinding(const ClientClasses& client_classes) {
+        if (client_classes.empty()) {
+            return(db::MySqlBinding::createNull());
+        }
+
+        // Create JSON list of client classes.
+        data::ElementPtr client_classes_element = data::Element::createList();
+        for (auto const& client_class : client_classes) {
+            client_classes_element->add(data::Element::create(client_class));
+        }
+
+        return (db::MySqlBinding::createString(client_classes_element->str()));
+    }
+
     /// @brief Creates input binding for user context parameter.
     ///
     /// @tparam T Type of the configuration element to which context belongs.
index 60b3e80ec2c5b5ff97d4df9e53ec7155ab2f9959..0a04b95c44a64791e67901976d1d15a4b2067425 100644 (file)
@@ -88,6 +88,7 @@ namespace {
     "  x.shared_network_name," \
     "  x.pool_id," \
     "  x.modification_ts," \
+    "  x.client_classes, " \
     "  o.option_id," \
     "  o.code," \
     "  o.value," \
@@ -101,6 +102,7 @@ namespace {
     "  o.shared_network_name," \
     "  o.pool_id," \
     "  o.modification_ts," \
+    "  o.client_classes, " \
     "  s.calculate_tee_times," \
     "  s.t1_percent," \
     "  s.t2_percent," \
@@ -314,7 +316,8 @@ namespace {
       "  x.user_context," \
       "  x.shared_network_name," \
       "  x.pool_id," \
-      "  x.modification_ts " \
+      "  x.modification_ts," \
+      "  x.client_classes " \
       "FROM dhcp4_pool AS p " \
       server_join \
       "LEFT JOIN dhcp4_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " \
@@ -448,6 +451,7 @@ namespace {
     "  o.shared_network_name," \
     "  o.pool_id," \
     "  o.modification_ts," \
+    "  o.client_classes," \
     "  n.calculate_tee_times," \
     "  n.t1_percent," \
     "  n.t2_percent," \
@@ -623,6 +627,7 @@ namespace {
     "  o.shared_network_name," \
     "  o.pool_id," \
     "  o.modification_ts," \
+    "  o.client_classes, " \
     "  s.tag " \
     pd_pool_id \
     "FROM " #table_prefix "_options AS o " \
@@ -719,6 +724,7 @@ namespace {
     "  x.shared_network_name," \
     "  x.pool_id," \
     "  x.modification_ts," \
+    "  x.client_classes," \
     "  s.tag " \
     "FROM dhcp4_client_class AS c " \
     "INNER JOIN dhcp4_client_class_order AS o " \
@@ -938,9 +944,10 @@ namespace {
     "  user_context," \
     "  shared_network_name," \
     "  pool_id," \
-    "  modification_ts" \
+    "  modification_ts," \
+    "  client_classes" \
     pd_pool_id \
-    ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?" last ")"
+    ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?" last ")"
 
 #define MYSQL_INSERT_OPTION4() \
     MYSQL_INSERT_OPTION_COMMON(dhcp4, "", "")
@@ -1058,7 +1065,8 @@ namespace {
     "  o.user_context = ?," \
     "  o.shared_network_name = ?," \
     "  o.pool_id = ?," \
-    "  o.modification_ts = ? " \
+    "  o.modification_ts = ?, " \
+    "  o.client_classes = ? " \
     pd_pool_id \
     "WHERE " #__VA_ARGS__
 
index b869a03128fd26ef23deb8f717825379505427f3..579f13709fe5f10076806f2ca371dbff7e5478a8 100644 (file)
@@ -82,6 +82,8 @@ constexpr unsigned long DNS_NAME_BUF_LENGTH = 255;
 
 constexpr unsigned long ALLOCATOR_TYPE_BUF_LENGTH = 64;
 
+constexpr unsigned long OPTION_CLIENT_CLASSES_BUF_LENGTH = 65536;
+
 //*}
 
 } // end of namespace isc::cb
index 87d7e67e902d18210f83b24f27d706d3f48e57ca..457f84dea5a03c7656e032c44438db8dfd7d1e96 100644 (file)
@@ -140,10 +140,7 @@ GenericConfigBackendDHCPv4Test::initTestSubnets() {
     subnet->addPool(pool2);
 
     // Add several options to the subnet.
-    subnet->getCfgOption()->add(test_options_[0]->option_,
-                                test_options_[0]->persistent_,
-                                test_options_[0]->cancelled_,
-                                test_options_[0]->space_name_);
+    subnet->getCfgOption()->add(*(test_options_[0]), test_options_[0]->space_name_);
 
     subnet->getCfgOption()->add(test_options_[1]->option_,
                                 test_options_[1]->persistent_,
@@ -337,6 +334,8 @@ GenericConfigBackendDHCPv4Test::initTestOptions() {
                                    true, false, false, "my-boot-file");
     desc.space_name_ = DHCP4_OPTION_SPACE;
     desc.setContext(user_context);
+    desc.addClientClass("class1");
+    desc.addClientClass("class2");
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
     desc = createOption<OptionUint8>(Option::V4, DHO_DEFAULT_IP_TTL,
@@ -368,6 +367,8 @@ GenericConfigBackendDHCPv4Test::initTestOptions() {
                                       true, false, false, "my-boot-file-2");
     desc.space_name_ = DHCP4_OPTION_SPACE;
     desc.setContext(user_context);
+    desc.addClientClass("class3");
+    desc.addClientClass("class4");
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
     desc = createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,