]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#719] Reapplied patch
authorFrancis Dupont <fdupont@isc.org>
Mon, 6 Mar 2023 16:34:30 +0000 (17:34 +0100)
committerFrancis Dupont <fdupont@isc.org>
Wed, 15 Mar 2023 12:49:21 +0000 (13:49 +0100)
75 files changed:
configure.ac
doc/examples/kea4/all-keys-netconf.json
doc/examples/kea4/all-keys.json
doc/examples/kea6/all-keys-netconf.json
doc/examples/kea6/all-keys.json
doc/sphinx/arm/dhcp4-srv.rst
doc/sphinx/arm/dhcp6-srv.rst
src/bin/admin/tests/mysql_tests.sh.in
src/bin/admin/tests/pgsql_tests.sh.in
src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp4/tests/config_backend_unittest.cc
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
src/bin/dhcp4/tests/dhcp4_test_utils.cc
src/bin/dhcp4/tests/get_config_unittest.cc
src/bin/dhcp4/tests/vendor_opts_unittest.cc
src/bin/dhcp6/dhcp6_lexer.ll
src/bin/dhcp6/dhcp6_parser.yy
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/tests/classify_unittests.cc
src/bin/dhcp6/tests/config_backend_unittest.cc
src/bin/dhcp6/tests/config_parser_unittest.cc
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/bin/dhcp6/tests/get_config_unittest.cc
src/bin/dhcp6/tests/vendor_opts_unittest.cc
src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc
src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.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/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc
src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc
src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc
src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h
src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h
src/lib/dhcpsrv/cfg_option.cc
src/lib/dhcpsrv/cfg_option.h
src/lib/dhcpsrv/mysql_host_data_source.cc
src/lib/dhcpsrv/parsers/option_data_parser.cc
src/lib/dhcpsrv/parsers/option_data_parser.h
src/lib/dhcpsrv/parsers/simple_parser4.cc
src/lib/dhcpsrv/parsers/simple_parser6.cc
src/lib/dhcpsrv/pgsql_host_data_source.cc
src/lib/dhcpsrv/tests/cb_ctl_dhcp_unittest.cc
src/lib/dhcpsrv/tests/cfg_option_unittest.cc
src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc
src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc
src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc
src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc
src/lib/dhcpsrv/tests/client_class_def_unittest.cc
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc
src/lib/dhcpsrv/tests/host_unittest.cc
src/lib/dhcpsrv/tests/pool_unittest.cc
src/lib/dhcpsrv/tests/srv_config_unittest.cc
src/lib/dhcpsrv/tests/subnet_unittest.cc
src/lib/dhcpsrv/testutils/generic_backend_unittest.cc
src/lib/dhcpsrv/testutils/generic_backend_unittest.h
src/lib/dhcpsrv/testutils/generic_cb_dhcp4_unittest.cc
src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.cc
src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc
src/lib/mysql/mysql_constants.h
src/lib/pgsql/pgsql_connection.h
src/lib/yang/tests/json_configs.h
src/lib/yang/tests/translator_option_data_unittests.cc
src/lib/yang/tests/yang_configs.h
src/lib/yang/translator_option_data.cc
src/lib/yang/translator_option_data.h
src/lib/yang/yang_revisions.h
src/share/database/scripts/mysql/Makefile.am
src/share/database/scripts/mysql/dhcpdb_create.mysql
src/share/database/scripts/pgsql/Makefile.am
src/share/database/scripts/pgsql/dhcpdb_create.pgsql

index 6ad90b2cada2c89271b5250d49cbec71d2b4d30d..914868d387bcced24e584b00e167ea24ceeaef7d 100644 (file)
@@ -1702,6 +1702,8 @@ AC_CONFIG_FILES([src/share/database/scripts/mysql/upgrade_012_to_013.sh],
                 [chmod +x src/share/database/scripts/mysql/upgrade_012_to_013.sh])
 AC_CONFIG_FILES([src/share/database/scripts/mysql/upgrade_013_to_014.sh],
                 [chmod +x src/share/database/scripts/mysql/upgrade_013_to_014.sh])
+AC_CONFIG_FILES([src/share/database/scripts/mysql/upgrade_014_to_015.sh],
+                [chmod +x src/share/database/scripts/mysql/upgrade_014_to_015.sh])
 AC_CONFIG_FILES([src/share/database/scripts/mysql/wipe_data.sh],
                 [chmod +x src/share/database/scripts/mysql/wipe_data.sh])
 AC_CONFIG_FILES([src/share/database/scripts/pgsql/Makefile])
@@ -1741,6 +1743,8 @@ AC_CONFIG_FILES([src/share/database/scripts/pgsql/upgrade_011_to_012.sh],
                 [chmod +x src/share/database/scripts/pgsql/upgrade_011_to_012.sh])
 AC_CONFIG_FILES([src/share/database/scripts/pgsql/upgrade_012_to_013.sh],
                 [chmod +x src/share/database/scripts/pgsql/upgrade_012_to_013.sh])
+AC_CONFIG_FILES([src/share/database/scripts/pgsql/upgrade_013_to_014.sh],
+                [chmod +x src/share/database/scripts/pgsql/upgrade_013_to_014.sh])
 AC_CONFIG_FILES([src/share/database/scripts/pgsql/wipe_data.sh],
                 [chmod +x src/share/database/scripts/pgsql/wipe_data.sh])
 AC_CONFIG_FILES([src/share/yang/Makefile])
index c333464799183eb92e9c3ea5f8b8924fc92868b4..8aa6366904b61d916735394b1a29426c32409d17 100644 (file)
                 // provided.
                 "name": "domain-name-servers",
 
+                // Boolean flag indicating if the given option is never
+                // send in response. The default value of false indicates
+                // that it is sent when it should. When true the option
+                // is not sent despite of any other setting, i.e. it is
+                // a final flag.
+                "never-send": false,
+
                 // Option space. The default is the "dhcp4" option space which
                 // groups top level DHCPv4 options.
                 "space": "dhcp4"
                                 // Option name.
                                 "name": "routers",
 
+                                // Boolean flag indicating if the given option is never
+                                // send in response.
+                                "never-send": false,
+
                                 // Option space. The default value "dhcp4" designates the
                                 // top level option space.
                                 "space": "dhcp4"
index ee29cbf1463d06fedc2c7c650020004b54a29af6..ccf01dde1f48fffa5b59ba88fdca5e42c886771a 100644 (file)
                 // provided.
                 "name": "domain-name-servers",
 
+                // Boolean flag indicating if the given option is never
+                // send in response. The default value of false indicates
+                // that it is sent when it should. When true the option
+                // is not sent despite of any other setting, i.e. it is
+                // a final flag.
+                "never-send": false,
+
                 // Option space. The default is the "dhcp4" option space which
                 // groups top level DHCPv4 options.
                 "space": "dhcp4"
                                 // Option name.
                                 "name": "routers",
 
+                                // Boolean flag indicating if the given option is never
+                                // send in response.
+                                "never-send": false,
+
                                 // Option space. The default value "dhcp4" designates the
                                 // top level option space.
                                 "space": "dhcp4"
index b3a043cd40edef61b8319f7f4c15fe6701e32b1b..990adf4a6df786ff57cfcc6b556e03edb5640690 100644 (file)
                 // provided.
                 "name": "dns-servers",
 
+                // Boolean flag indicating if the given option is never
+                // send in response. The default value of false indicates
+                // that it is sent when it should. When true the option
+                // is not sent despite of any other setting, i.e. it is
+                // a final flag.
+                "never-send": false,
+
                 // Option space. The default is the "dhcp6" option space which
                 // groups top level DHCPv6 options.
                 "space": "dhcp6"
                                 // Option name.
                                 "name": "preference",
 
+                                // Boolean flag indicating if the given option is never
+                                // send in response.
+                                "never-send": false,
+
                                 // Option space. The default value "dhcp6" designates the
                                 // top level option space.
                                 "space": "dhcp6"
index e657492e15372b3abd54189d107e11738068a3e1..81e113c309e2d51a40bf9f5fec380b343b099288 100644 (file)
                 // provided.
                 "name": "dns-servers",
 
+                // Boolean flag indicating if the given option is never
+                // send in response. The default value of false indicates
+                // that it is sent when it should. When true the option
+                // is not sent despite of any other setting, i.e. it is
+                // a final flag.
+                "never-send": false,
+
                 // Option space. The default is the "dhcp6" option space which
                 // groups top level DHCPv6 options.
                 "space": "dhcp6"
                                 // Option name.
                                 "name": "preference",
 
+                                // Boolean flag indicating if the given option is never
+                                // send in response.
+                                "never-send": false,
+
                                 // Option space. The default value "dhcp6" designates the
                                 // top level option space.
                                 "space": "dhcp6"
index 649415f124a219680d7f9065f936fdbc00609188..149988a2980ea9853d96502ccf400ab6ec258025 100644 (file)
@@ -1490,6 +1490,49 @@ The ``domain-name-servers`` option is always added to responses (the
 always-send is "sticky"), but the value is the subnet one when the client
 is localized in the subnet.
 
+At the opposite of ``always-send`` if the ``never-send`` flag is set to
+``true`` for a particular option the server does not add it to the response.
+The effect is the same as if the client removed the option code in the
+Parameter Request List option Option (or its equivalent for vendor options):
+
+::
+
+   "Dhcp4": {
+       "option-data": [
+           {
+              "name": "domain-name-servers",
+              "data": "192.0.2.1, 192.0.2.2"
+           },
+           ...
+       ],
+       "subnet4": [
+           {
+              "subnet": "192.0.3.0/24",
+              "option-data": [
+                  {
+                      "name": "domain-name-servers",
+                      "never-send": true
+                  },
+                  ...
+              ],
+              ...
+           },
+           ...
+       ],
+       ...
+   }
+
+The ``domain-name-servers`` option is never added to responses (the
+never-send is "sticky" too). The ``never-send`` is as the precedence
+over ``always-send`` so if both are true the option is not added.
+
+.. note::
+
+   The ``never-send`` is less powerful than the :ref:`hooks-flex-option`,
+   for instance it has no effect on options managed by the server itself.
+   Both ``always-send`` and ``never-send`` has no effect too on options
+   which cannot be requested, for instance from a custom space.
+
 The ``name`` parameter specifies the option name. For a list of
 currently supported names, see :ref:`dhcp4-std-options-list`
 below. The ``code`` parameter specifies the option code, which must
index 4e0b4605aaa09f65f987e112a54aca9a0a0fc09f..594d6c4aaf48ec860dd201157c454f724f6489c2 100644 (file)
@@ -1417,6 +1417,49 @@ The ``dns-servers`` option is always added to responses (the always-send is
 "sticky"), but the value is the subnet one when the client is localized
 in the subnet.
 
+At the opposite of ``always-send`` if the ``never-send`` flag is set to
+``true`` for a particular option the server does not add it to the response.
+The effect is the same as if the client removed the option code in the
+Option Request Option (or its equivalent for vendor options), as in:
+
+::
+
+   "Dhcp6": {
+       "option-data": [
+           {
+              "name": "dns-servers",
+              "data": "2001:db8::cafe, 2001:db8::babe"
+           },
+           ...
+       ],
+       "subnet6": [
+           {
+              "subnet": "2001:db8:1::/64",
+              "option-data": [
+                  {
+                      "name": "dns-servers",
+                      "never-send": true
+                  },
+                  ...
+              ],
+              ...
+           },
+           ...
+       ],
+       ...
+   }
+
+The ``dns-server`` option is never added to responses (the never-send is
+"sticky" too). The ``never-send`` is as the precedence over ``always-send``
+so if both are true the option is not added.
+
+.. note::
+
+   The ``never-send`` is less powerful than the :ref:`hooks-flex-option`,
+   for instance it has no effect on options managed by the server itself.
+   Both ``always-send`` and ``never-send`` has no effect too on options
+   which cannot be requested, for instance from a custom space.
+
 It is possible to override options on a per-subnet basis. If clients
 connected to most subnets are expected to get the same values of
 a given option, administrators should use global options; it is possible to override
index ceb541c5995845b2e0f2e0f010ff43dd9127528d..403d51ea9803ba8a1565f15058a8c1d270b6d468 100644 (file)
@@ -708,7 +708,7 @@ mysql_upgrade_test() {
 
     # Verify that the upgraded schema reports the latest version.
     version=$("${kea_admin}" db-version mysql -u "${db_user}" -p "${db_password}" -n "${db_name}" -d "${db_scripts_dir}")
-    assert_str_eq "14.0" "${version}" "Expected kea-admin to return %s, returned value was %s"
+    assert_str_eq "15.0" "${version}" "Expected kea-admin to return %s, returned value was %s"
 
     # Let's check that the new tables are indeed there.
 
@@ -1335,6 +1335,16 @@ SET @disable_audit = 0;"
     # Check upgrade from 13.0 to 14.0.
     mysql_upgrade_13_to_14_test
 
+    # Check upgrade from 14.0 to 15.0.
+
+    # table: dhcp4_options new cancelled column.
+    qry="select cancelled from dhcp4_options"
+    run_statement "dhcp4_options" "$qry"
+
+    # table: dhcp6_options new cancelled column.
+    qry="select cancelled from dhcp6_options"
+    run_statement "dhcp6_options" "$qry"
+
     # Let's wipe the whole database
     mysql_wipe
 
index a9704c394f83344a3724a8ff3685ffa9cfc07e8d..275f4df958634b16d128286472fcbd401a29d3de 100644 (file)
@@ -143,7 +143,7 @@ pgsql_db_version_test() {
     run_command \
         "${kea_admin}" db-version pgsql -u "${db_user}" -p "${db_password}" -n "${db_name}"
     version="${OUTPUT}"
-    assert_str_eq "13.0" "${version}" "Expected kea-admin to return %s, returned value was %s"
+    assert_str_eq "14.0" "${version}" "Expected kea-admin to return %s, returned value was %s"
 
     # Let's wipe the whole database
     pgsql_wipe
@@ -760,6 +760,18 @@ pgsql_upgrade_12_to_13_test() {
     done
 }
 
+pgsql_upgrade_13_to_14_test() {
+    # Added cancelled column to dhcp4_options
+    run_command \
+        pgsql_execute "select cancelled from dhcp4_options;"
+    assert_eq 0 "${EXIT_CODE}" "dhcp4_options is missing cancelled column. (expected status  code %d, returned %d)"
+
+    # Added cancelled column to dhcp6_options
+    run_command \
+        pgsql_execute "select cancelled from dhcp6_options;"
+    assert_eq 0 "${EXIT_CODE}" "dhcp6_options is missing cancelled column. (expected status  code %d, returned %d)"
+}
+
 pgsql_upgrade_test() {
     test_start "pgsql.upgrade"
 
@@ -777,7 +789,7 @@ pgsql_upgrade_test() {
 
     # Verify upgraded schema reports the latest version.
     version=$("${kea_admin}" db-version pgsql -u "${db_user}" -p "${db_password}" -n "${db_name}" -d "${db_scripts_dir}")
-    assert_str_eq "13.0" "${version}" 'Expected kea-admin to return %s, returned value was %s'
+    assert_str_eq "14.0" "${version}" 'Expected kea-admin to return %s, returned value was %s'
 
     # Check 1.0 to 2.0 upgrade
     pgsql_upgrade_1_0_to_2_0
@@ -812,6 +824,9 @@ pgsql_upgrade_test() {
     # Check 12 to 13 upgrade
     pgsql_upgrade_12_to_13_test
 
+    # Check 13 to 14 upgrade
+    pgsql_upgrade_13_to_14_test
+
     # Let's wipe the whole database
     pgsql_wipe
 
index 992810232d49a06f066a7458791e22f7213f38fd..ed105269d601251e090046bd54e5dd9f62ac33b6 100644 (file)
@@ -946,6 +946,15 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     }
 }
 
+\"never-send\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::OPTION_DATA:
+        return isc::dhcp::Dhcp4Parser::make_NEVER_SEND(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("never-send", driver.loc_);
+    }
+}
+
 \"pools\" {
     switch(driver.ctx_) {
     case isc::dhcp::Parser4Context::SUBNET4:
index 255d89cbabea513337416a338e20e4bf8003f667..98c8d3c4cbee0566c2303e16e32567b3a275334e 100644 (file)
@@ -144,6 +144,7 @@ using namespace std;
   SPACE "space"
   CSV_FORMAT "csv-format"
   ALWAYS_SEND "always-send"
+  NEVER_SEND "never-send"
   RECORD_TYPES "record-types"
   ENCAPSULATE "encapsulate"
   ARRAY "array"
@@ -1972,6 +1973,7 @@ option_data_param: option_data_name
                  | option_data_space
                  | option_data_csv_format
                  | option_data_always_send
+                 | option_data_never_send
                  | user_context
                  | comment
                  | unknown_map_entry
@@ -2004,6 +2006,12 @@ option_data_always_send: ALWAYS_SEND COLON BOOLEAN {
     ctx.stack_.back()->set("always-send", persist);
 };
 
+option_data_never_send: NEVER_SEND COLON BOOLEAN {
+    ctx.unique("never-send", ctx.loc2pos(@1));
+    ElementPtr persist(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("never-send", persist);
+};
+
 // ---- pools ------------------------------------
 
 // This defines the "pools": [ ... ] entry that may appear in subnet4.
index df565b0d8796b73714353aa912dc7671bed20cfd..d5010555e67d782f1aabacb84efd89b6f8217b9b 100644 (file)
@@ -1841,33 +1841,50 @@ Dhcpv4Srv::appendRequestedOptions(Dhcpv4Exchange& ex) {
         }
     }
 
-    // Iterate on the configured option list to add persistent options
+    std::set<uint8_t> cancelled_opts;
+
+    // Iterate on the configured option list to add persistent and
+    // cancelled options.
     for (auto const& copts : co_list) {
         const OptionContainerPtr& opts = copts->getAll(DHCP4_OPTION_SPACE);
         if (!opts) {
             continue;
         }
-        // Get persistent options
-        const OptionContainerPersistIndex& idx = opts->get<2>();
-        const OptionContainerPersistRange& range = idx.equal_range(true);
-        for (OptionContainerPersistIndex::const_iterator desc = range.first;
-             desc != range.second; ++desc) {
-            // Add the persistent option code to requested options
+        // Get persistent options.
+        const OptionContainerPersistIndex& pidx = opts->get<2>();
+        const OptionContainerPersistRange& prange = pidx.equal_range(true);
+        for (OptionContainerPersistIndex::const_iterator desc = prange.first;
+             desc != prange.second; ++desc) {
+            // Add the persistent option code to requested options.
             if (desc->option_) {
-                uint16_t code = desc->option_->getType();
+                uint8_t code = static_cast<uint8_t>(desc->option_->getType());
                 static_cast<void>(requested_opts.insert(code));
             }
         }
-    }
+        // Get cancelled options.
+        const OptionContainerCancelIndex& cidx = opts->get<5>();
+        const OptionContainerCancelRange& crange = cidx.equal_range(true);
+        for (OptionContainerCancelIndex::const_iterator desc = crange.first;
+             desc != crange.second; ++desc) {
+            // Add the cancelled option code to cancelled options.
+            if (desc->option_) {
+                uint8_t code = static_cast<uint8_t>(desc->option_->getType());
+                static_cast<void>(cancelled_opts.insert(code));
+            }
+        }
+        }
 
     // For each requested option code get the first instance of the option
     // to be returned to the client.
-    for (auto const& opt : requested_opts) {
-        // Add nothing when it is already there.
+    for (uint8_t opt : requested_opts) {
+        if (cancelled_opts.count(opt) > 0) {
+            continue;
+        }
         // Skip special cases: DHO_VIVSO_SUBOPTIONS.
         if (opt == DHO_VIVSO_SUBOPTIONS) {
             continue;
         }
+        // Add nothing when it is already there.
         if (!resp->getOption(opt)) {
             // Iterate on the configured option list
             for (auto const& copts : co_list) {
@@ -1883,7 +1900,8 @@ Dhcpv4Srv::appendRequestedOptions(Dhcpv4Exchange& ex) {
 
     // Special cases for vendor class and options which are identified
     // by the code/type and the vendor/enterprise id vs. the code/type only.
-    if (requested_opts.count(DHO_VIVCO_SUBOPTIONS) > 0) {
+    if ((requested_opts.count(DHO_VIVCO_SUBOPTIONS) > 0) &&
+        (cancelled_opts.count(DHO_VIVCO_SUBOPTIONS) == 0)) {
         // Keep vendor ids which are already in the response to insert
         // VIVCO options at most once per vendor.
         set<uint32_t> vendor_ids;
@@ -1920,7 +1938,8 @@ Dhcpv4Srv::appendRequestedOptions(Dhcpv4Exchange& ex) {
         }
     }
 
-    if (requested_opts.count(DHO_VIVSO_SUBOPTIONS) > 0) {
+    if ((requested_opts.count(DHO_VIVSO_SUBOPTIONS) > 0) &&
+        (cancelled_opts.count(DHO_VIVSO_SUBOPTIONS) == 0)) {
         // Keep vendor ids which are already in the response to insert
         // VIVSO options at most once per vendor.
         set<uint32_t> vendor_ids;
@@ -2050,24 +2069,40 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
         }
     }
 
-    // Iterate on the configured option list to add persistent options
     for (uint32_t vendor_id : vendor_ids) {
+
+        std::set<uint8_t> cancelled_opts;
+
+        // Iterate on the configured option list to add persistent and
+        // cancelled options,
         for (auto const& copts : co_list) {
             const OptionContainerPtr& opts = copts->getAll(vendor_id);
             if (!opts) {
                 continue;
             }
-            // Get persistent options
-            const OptionContainerPersistIndex& idx = opts->get<2>();
-            const OptionContainerPersistRange& range = idx.equal_range(true);
-            for (OptionContainerPersistIndex::const_iterator desc = range.first;
-                 desc != range.second; ++desc) {
-                if (!desc->option_) {
-                    continue;
+
+            // Get persistent options.
+            const OptionContainerPersistIndex& pidx = opts->get<2>();
+            const OptionContainerPersistRange& prange = pidx.equal_range(true);
+            for (OptionContainerPersistIndex::const_iterator desc = prange.first;
+                 desc != prange.second; ++desc) {
+                // Add the persistent option code to requested options.
+                if (desc->option_) {
+                    uint8_t code = static_cast<uint8_t>(desc->option_->getType());
+                    static_cast<void>(requested_opts[vendor_id].insert(code));
+                }
+            }
+
+            // Get cancelled options.
+            const OptionContainerCancelIndex& cidx = opts->get<5>();
+            const OptionContainerCancelRange& crange = cidx.equal_range(true);
+            for (OptionContainerCancelIndex::const_iterator desc = crange.first;
+                 desc != crange.second; ++desc) {
+                // Add the cancelled option code to cancelled options.
+                if (desc->option_) {
+                    uint8_t code = static_cast<uint8_t>(desc->option_->getType());
+                    static_cast<void>(cancelled_opts.insert(code));
                 }
-                // Add the persistent option code to requested options
-                uint16_t code = desc->option_->getType();
-                static_cast<void>(requested_opts[vendor_id].insert(code));
             }
         }
 
@@ -2080,8 +2115,9 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
             continue;
         }
 
-        // It's possible that the vendor opts option was inserted already
-        // by client class or a hook. If that is so, let's use it.
+
+        // It's possible that vivso was inserted already by client class or
+        // a hook. If that is so, let's use it.
         OptionVendorPtr vendor_rsp;
         if (vendor_rsps.count(vendor_id) > 0) {
             vendor_rsp = vendor_rsps[vendor_id];
@@ -2093,6 +2129,9 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
         bool added = false;
 
         for (uint8_t opt : requested_opts[vendor_id]) {
+            if (cancelled_opts.count(opt) > 0) {
+                continue;
+            }
             if (!vendor_rsp->getOption(opt)) {
                 for (auto const& copts : co_list) {
                     OptionDescriptor desc = copts->get(vendor_id, opt);
index ce1b78d499b170bf6444049a68e4fa54c50372a7..4cd146fe2e758c2ac5ccb8f0d36e0edb1815bfdb 100644 (file)
@@ -337,21 +337,24 @@ TEST_F(Dhcp4CBTest, mergeOptions) {
     // Add host-name to the first backend.
     opt.reset(new OptionDescriptor(
               createOption<OptionString>(Option::V4, DHO_HOST_NAME,
-                                         true, false, "new.example.com")));
+                                         true, false, false,
+                                         "new.example.com")));
     opt->space_name_ = DHCP4_OPTION_SPACE;
     db1_->createUpdateOption4(ServerSelector::ALL(), opt);
 
     // Add boot-file-name to the first backend.
     opt.reset(new OptionDescriptor(
               createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
-                                         true, false, "my-boot-file")));
+                                         true, false, false,
+                                         "my-boot-file")));
     opt->space_name_ = DHCP4_OPTION_SPACE;
     db1_->createUpdateOption4(ServerSelector::ALL(), opt);
 
     // Add boot-file-name to the second backend.
     opt.reset(new OptionDescriptor(
               createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
-                                         true, false, "your-boot-file")));
+                                         true, false, false,
+                                         "your-boot-file")));
     opt->space_name_ = DHCP4_OPTION_SPACE;
     db2_->createUpdateOption4(ServerSelector::ALL(), opt);
 
index d04c3f7e3f977a7246f7c683f3877c9f9fedfa2e..4077ce15dbf5ae13f149963d895b7b0501e6835d 100644 (file)
@@ -510,7 +510,7 @@ public:
                           << subnet_address.toText() << "'. Expected "
                 " at most one option";
         } else if (std::distance(range.first, range.second) == 0) {
-            return (OptionDescriptor(OptionPtr(), false));
+            return (OptionDescriptor(OptionPtr(), false, false));
         }
 
         return (*range.first);
index d4d3acfc9f52a6ab85482d4958563b5f31b16814..c4b7064a864ec320e1a31e12464400e0793745a2 100644 (file)
@@ -135,6 +135,39 @@ const char* CONFIGS[] = {
     "}",
 
     // Configuration 3:
+    // - 1 subnet with never-send option
+    // - 2 global options (one forced with always-send)
+    "{"
+    "    \"interfaces-config\": {"
+    "    \"interfaces\": [ \"*\" ] }, "
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"valid-lifetime\": 4000, "
+    "    \"subnet4\": [ {"
+    "        \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ], "
+    "        \"subnet\": \"192.0.2.0/24\","
+    "        \"option-data\": ["
+    "            {"
+    "                \"name\": \"ip-forwarding\", "
+    "                \"never-send\": true"
+    "            }"
+    "        ]"
+    "    } ], "
+    "    \"option-data\": ["
+    "        {"
+    "            \"name\": \"default-ip-ttl\", "
+    "            \"data\": \"FF\", "
+    "            \"csv-format\": false"
+    "        }, "
+    "        {"
+    "            \"name\": \"ip-forwarding\", "
+    "            \"data\": \"false\", "
+    "            \"always-send\": true"
+    "        }"
+    "    ]"
+    "}",
+
+    // Configuration 4:
     // - one subnet, with one pool
     // - user-contexts defined in both subnet and pool
     "{"
@@ -4069,7 +4102,7 @@ TEST_F(Dhcpv4SrvTest, privateOption) {
     EXPECT_EQ(12345678, opt32->getValue());
 }
 
-// Checks effect of persistency (aka always-true) flag on the PRL
+// Checks effect of persistency (aka always-send) flag on the PRL.
 TEST_F(Dhcpv4SrvTest, prlPersistency) {
     IfaceMgrTestConfig test_config(true);
 
@@ -4122,6 +4155,59 @@ TEST_F(Dhcpv4SrvTest, prlPersistency) {
     ASSERT_FALSE(response->getOption(DHO_ARP_CACHE_TIMEOUT));
 }
 
+// Checks effect of cancellation (aka never-send) flag.
+TEST_F(Dhcpv4SrvTest, neverSend) {
+    IfaceMgrTestConfig test_config(true);
+
+    ASSERT_NO_THROW(configure(CONFIGS[3]));
+
+    // Create a packet with enough to select the subnet and go through
+    // the DISCOVER processing
+    Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 1234));
+    query->setRemoteAddr(IOAddress("192.0.2.1"));
+    OptionPtr clientid = generateClientId();
+    query->addOption(clientid);
+    query->setIface("eth1");
+    query->setIndex(ETH1_INDEX);
+
+    // Create and add a PRL option for another option
+    OptionUint8ArrayPtr prl(new OptionUint8Array(Option::V4,
+                                                 DHO_DHCP_PARAMETER_REQUEST_LIST));
+    ASSERT_TRUE(prl);
+    prl->addValue(DHO_ARP_CACHE_TIMEOUT);
+    query->addOption(prl);
+
+    // Create and add a host-name option to the query
+    OptionStringPtr hostname(new OptionString(Option::V4, 12, "foo"));
+    ASSERT_TRUE(hostname);
+    query->addOption(hostname);
+
+    // Let the server process it.
+    Pkt4Ptr response = srv_.processDiscover(query);
+
+    // Processing should not add an ip-forwarding option
+    ASSERT_FALSE(response->getOption(DHO_IP_FORWARDING));
+    // And no default-ip-ttl
+    ASSERT_FALSE(response->getOption(DHO_DEFAULT_IP_TTL));
+    // Nor an arp-cache-timeout
+    ASSERT_FALSE(response->getOption(DHO_ARP_CACHE_TIMEOUT));
+
+    // Reset PRL adding default-ip-ttl
+    query->delOption(DHO_DHCP_PARAMETER_REQUEST_LIST);
+    prl->addValue(DHO_DEFAULT_IP_TTL);
+    query->addOption(prl);
+
+    // Let the server process it again.
+    response = srv_.processDiscover(query);
+
+    // Processing should not add an ip-forwarding option
+    ASSERT_FALSE(response->getOption(DHO_IP_FORWARDING));
+    // And now a default-ip-ttl
+    ASSERT_TRUE(response->getOption(DHO_DEFAULT_IP_TTL));
+    // And still no arp-cache-timeout
+    ASSERT_FALSE(response->getOption(DHO_ARP_CACHE_TIMEOUT));
+}
+
 // Checks if relay IP address specified in the relay-info structure in
 // subnet4 is being used properly.
 TEST_F(Dhcpv4SrvTest, relayOverride) {
@@ -4904,7 +4990,7 @@ TEST_F(Dhcpv4SrvTest, userContext) {
 
     // This config has one subnet with user-context with one
     // pool (also with context). Make sure the configuration could be accepted.
-    EXPECT_NO_THROW(configure(CONFIGS[3]));
+    EXPECT_NO_THROW(configure(CONFIGS[4]));
 
     // Now make sure the data was not lost.
     ConstSrvConfigPtr cfg = CfgMgr::instance().getCurrentCfg();
index 01596e6550646f094d4ba81535a497179cb7ba1e..7bfbe01550f2309e879384baa2b56b848db5b729 100644 (file)
@@ -69,7 +69,8 @@ Dhcpv4SrvTest::Dhcpv4SrvTest()
     // Add Router option.
     Option4AddrLstPtr opt_routers(new Option4AddrLst(DHO_ROUTERS));
     opt_routers->setAddress(IOAddress("192.0.2.2"));
-    subnet_->getCfgOption()->add(opt_routers, false, DHCP4_OPTION_SPACE);
+    subnet_->getCfgOption()->add(opt_routers, false, false,
+                                 DHCP4_OPTION_SPACE);
 
     CfgMgr::instance().clear();
     CfgMgr::instance().setFamily(AF_INET);
@@ -133,25 +134,29 @@ Dhcpv4SrvTest::configureRequestedOptions() {
         option_dns_servers(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS));
     option_dns_servers->addAddress(IOAddress("192.0.2.1"));
     option_dns_servers->addAddress(IOAddress("192.0.2.100"));
-    ASSERT_NO_THROW(subnet_->getCfgOption()->add(option_dns_servers, false, DHCP4_OPTION_SPACE));
+    ASSERT_NO_THROW(subnet_->getCfgOption()->add(option_dns_servers, false,
+                                                 false, DHCP4_OPTION_SPACE));
 
     // domain-name
     OptionDefinition def("domain-name", DHO_DOMAIN_NAME, DHCP4_OPTION_SPACE,
                          OPT_FQDN_TYPE);
     OptionCustomPtr option_domain_name(new OptionCustom(def, Option::V4));
     option_domain_name->writeFqdn("example.com");
-    subnet_->getCfgOption()->add(option_domain_name, false, DHCP4_OPTION_SPACE);
+    subnet_->getCfgOption()->add(option_domain_name, false, false,
+                                 DHCP4_OPTION_SPACE);
 
     // log-servers
     Option4AddrLstPtr option_log_servers(new Option4AddrLst(DHO_LOG_SERVERS));
     option_log_servers->addAddress(IOAddress("192.0.2.2"));
     option_log_servers->addAddress(IOAddress("192.0.2.10"));
-    ASSERT_NO_THROW(subnet_->getCfgOption()->add(option_log_servers, false, DHCP4_OPTION_SPACE));
+    ASSERT_NO_THROW(subnet_->getCfgOption()->add(option_log_servers, false,
+                                                 false, DHCP4_OPTION_SPACE));
 
     // cookie-servers
     Option4AddrLstPtr option_cookie_servers(new Option4AddrLst(DHO_COOKIE_SERVERS));
     option_cookie_servers->addAddress(IOAddress("192.0.2.1"));
-    ASSERT_NO_THROW(subnet_->getCfgOption()->add(option_cookie_servers, false, DHCP4_OPTION_SPACE));
+    ASSERT_NO_THROW(subnet_->getCfgOption()->add(option_cookie_servers, false,
+                                                 false, DHCP4_OPTION_SPACE));
 }
 
 void
@@ -165,7 +170,7 @@ Dhcpv4SrvTest::configureServerIdentifier() {
     // Add server identifier to the pool.
     OptionCustomPtr server_id = makeServerIdOption(IOAddress("192.0.2.254"));
     CfgOptionPtr cfg_option = pool->getCfgOption();
-    cfg_option->add(server_id, false, DHCP4_OPTION_SPACE);
+    cfg_option->add(server_id, false, false, DHCP4_OPTION_SPACE);
     subnet2->addPool(pool);
 
     // Add a second pool.
@@ -186,7 +191,7 @@ Dhcpv4SrvTest::configureServerIdentifier() {
     // Add server identifier.
     server_id = makeServerIdOption(IOAddress("192.0.3.254"));
     cfg_option = subnet3->getCfgOption();
-    cfg_option->add(server_id, false, DHCP4_OPTION_SPACE);
+    cfg_option->add(server_id, false, false, DHCP4_OPTION_SPACE);
 
     subnets->add(subnet3);
 
@@ -207,7 +212,7 @@ Dhcpv4SrvTest::configureServerIdentifier() {
     subnets->add(subnet5);
 
     CfgOptionPtr options(new CfgOption());
-    OptionDescriptor desc(false);
+    OptionDescriptor desc(false, false);
     desc.option_ = makeServerIdOption(IOAddress("192.0.5.254"));
     options->add(desc, DHCP4_OPTION_SPACE);
     CfgMgr::instance().getStagingCfg()->getClientClassDictionary()->addClass("foo", ExpressionPtr(), "", true, false, options);
@@ -222,7 +227,7 @@ Dhcpv4SrvTest::configureServerIdentifier() {
     subnets->add(subnet6);
 
     options.reset(new CfgOption());
-    OptionDescriptor desc_other(false);
+    OptionDescriptor desc_other(false, false);
     desc_other.option_ = makeFqdnListOption();
     options->add(desc_other, DHCP4_OPTION_SPACE);
     CfgMgr::instance().getStagingCfg()->getClientClassDictionary()->addClass("bar", ExpressionPtr(), "", true, false, options);
@@ -248,14 +253,14 @@ Dhcpv4SrvTest::configureServerIdentifier() {
     // Add server identifier.
     server_id = makeServerIdOption(IOAddress("192.0.4.254"));
     cfg_option = network1->getCfgOption();
-    cfg_option->add(server_id, false, DHCP4_OPTION_SPACE);
+    cfg_option->add(server_id, false, false, DHCP4_OPTION_SPACE);
 
     networks->add(network1);
 
     // Add a global server identifier.
     cfg_option = cfg_mgr.getStagingCfg()->getCfgOption();
     server_id = makeServerIdOption(IOAddress("10.0.0.254"));
-    cfg_option->add(server_id, false, DHCP4_OPTION_SPACE);
+    cfg_option->add(server_id, false, false, DHCP4_OPTION_SPACE);
 
     // Commit the config.
     cfg_mgr.commit();
index 11e722e4dc017dd5dc5c4329a67f18791eaa3610..be9b62dc69eece28f9ce0b5f0d84a79edc9bf4be 100644 (file)
@@ -5549,6 +5549,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": false,\n"
 "                \"data\": \"ABCDEF0105\",\n"
 "                \"name\": \"dhcp-message\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp4\"\n"
 "            },\n"
 "            {\n"
@@ -5557,6 +5558,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": false,\n"
 "                \"data\": \"01\",\n"
 "                \"name\": \"default-ip-ttl\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp4\"\n"
 "            }\n"
 "        ],\n"
@@ -5708,6 +5710,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": false,\n"
 "                        \"data\": \"ABCDEF0105\",\n"
 "                        \"name\": \"dhcp-message\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp4\"\n"
 "                    },\n"
 "                    {\n"
@@ -5716,6 +5719,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": false,\n"
 "                        \"data\": \"01\",\n"
 "                        \"name\": \"default-ip-ttl\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp4\"\n"
 "                    }\n"
 "                ],\n"
@@ -5809,6 +5813,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": false,\n"
 "                \"data\": \"ABCDEF0105\",\n"
 "                \"name\": \"dhcp-message\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp4\"\n"
 "            },\n"
 "            {\n"
@@ -5817,6 +5822,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"1234\",\n"
 "                \"name\": \"foo\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"isc\"\n"
 "            }\n"
 "        ],\n"
@@ -5949,6 +5955,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"1234\",\n"
 "                \"name\": \"foo\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"isc\"\n"
 "            },\n"
 "            {\n"
@@ -5957,6 +5964,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"192.168.2.1\",\n"
 "                \"name\": \"foo2\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"isc\"\n"
 "            }\n"
 "        ],\n"
@@ -6069,6 +6077,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"11\",\n"
 "                \"name\": \"base-option\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp4\"\n"
 "            },\n"
 "            {\n"
@@ -6077,6 +6086,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"1234\",\n"
 "                \"name\": \"foo\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"isc\"\n"
 "            },\n"
 "            {\n"
@@ -6085,6 +6095,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"192.168.2.1\",\n"
 "                \"name\": \"foo2\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"isc\"\n"
 "            }\n"
 "        ],\n"
@@ -6235,6 +6246,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": false,\n"
 "                \"data\": \"AB\",\n"
 "                \"name\": \"dhcp-message\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp4\"\n"
 "            }\n"
 "        ],\n"
@@ -6273,6 +6285,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": false,\n"
 "                        \"data\": \"ABCDEF0105\",\n"
 "                        \"name\": \"dhcp-message\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp4\"\n"
 "                    },\n"
 "                    {\n"
@@ -6281,6 +6294,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": false,\n"
 "                        \"data\": \"01\",\n"
 "                        \"name\": \"default-ip-ttl\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp4\"\n"
 "                    }\n"
 "                ],\n"
@@ -6403,6 +6417,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": false,\n"
 "                        \"data\": \"0102030405060708090A\",\n"
 "                        \"name\": \"dhcp-message\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp4\"\n"
 "                    }\n"
 "                ],\n"
@@ -6440,6 +6455,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": false,\n"
 "                        \"data\": \"FF\",\n"
 "                        \"name\": \"default-ip-ttl\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp4\"\n"
 "                    }\n"
 "                ],\n"
@@ -6565,6 +6581,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": false,\n"
 "                                \"data\": \"ABCDEF0105\",\n"
 "                                \"name\": \"dhcp-message\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp4\"\n"
 "                            },\n"
 "                            {\n"
@@ -6573,6 +6590,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": false,\n"
 "                                \"data\": \"01\",\n"
 "                                \"name\": \"default-ip-ttl\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp4\"\n"
 "                            }\n"
 "                        ],\n"
@@ -6695,6 +6713,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": false,\n"
 "                                \"data\": \"ABCDEF0105\",\n"
 "                                \"name\": \"dhcp-message\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp4\"\n"
 "                            }\n"
 "                        ],\n"
@@ -6708,6 +6727,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": false,\n"
 "                                \"data\": \"01\",\n"
 "                                \"name\": \"default-ip-ttl\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp4\"\n"
 "                            }\n"
 "                        ],\n"
@@ -6798,6 +6818,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"true, 10.0.0.3, 127.0.0.1\",\n"
 "                \"name\": \"slp-directory-agent\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp4\"\n"
 "            },\n"
 "            {\n"
@@ -6806,6 +6827,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"false, \",\n"
 "                \"name\": \"slp-service-scope\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp4\"\n"
 "            }\n"
 "        ],\n"
@@ -6928,6 +6950,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"1234\",\n"
 "                \"name\": \"foo\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"vendor-encapsulated-options-space\"\n"
 "            },\n"
 "            {\n"
@@ -6936,6 +6959,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"192.168.2.1\",\n"
 "                \"name\": \"foo2\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"vendor-encapsulated-options-space\"\n"
 "            }\n"
 "        ],\n"
@@ -7048,6 +7072,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": false,\n"
 "                \"data\": \"0104000004D20204C0A80201\",\n"
 "                \"name\": \"vendor-encapsulated-options\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp4\"\n"
 "            },\n"
 "            {\n"
@@ -7056,6 +7081,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"1234\",\n"
 "                \"name\": \"foo\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"vendor-encapsulated-options-space\"\n"
 "            },\n"
 "            {\n"
@@ -7064,6 +7090,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"192.168.2.1\",\n"
 "                \"name\": \"foo2\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"vendor-encapsulated-options-space\"\n"
 "            }\n"
 "        ],\n"
@@ -7204,6 +7231,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"code\": 100,\n"
 "                \"csv-format\": false,\n"
 "                \"data\": \"1234\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"vendor-1234\"\n"
 "            },\n"
 "            {\n"
@@ -7211,6 +7239,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"code\": 100,\n"
 "                \"csv-format\": false,\n"
 "                \"data\": \"ABCDEF0105\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"vendor-4491\"\n"
 "            }\n"
 "        ],\n"
@@ -7333,6 +7362,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"this is a string vendor-opt\",\n"
 "                \"name\": \"foo\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"vendor-4491\"\n"
 "            }\n"
 "        ],\n"
@@ -8603,6 +8633,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"192.0.3.95\",\n"
 "                                \"name\": \"name-servers\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp4\"\n"
 "                            },\n"
 "                            {\n"
@@ -8611,6 +8642,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"11\",\n"
 "                                \"name\": \"default-ip-ttl\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp4\"\n"
 "                            }\n"
 "                        ],\n"
@@ -8630,6 +8662,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"192.0.3.15\",\n"
 "                                \"name\": \"name-servers\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp4\"\n"
 "                            },\n"
 "                            {\n"
@@ -8638,6 +8671,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"32\",\n"
 "                                \"name\": \"default-ip-ttl\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp4\"\n"
 "                            }\n"
 "                        ],\n"
@@ -8706,6 +8740,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"192.0.4.11\",\n"
 "                                \"name\": \"name-servers\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp4\"\n"
 "                            },\n"
 "                            {\n"
@@ -8714,6 +8749,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"95\",\n"
 "                                \"name\": \"default-ip-ttl\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp4\"\n"
 "                            }\n"
 "                        ],\n"
@@ -8857,6 +8893,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"123\",\n"
 "                                \"name\": \"foo\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"isc\"\n"
 "                            }\n"
 "                        ],\n"
@@ -11284,6 +11321,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": false,\n"
 "                \"data\": \"ABCDEF0105\",\n"
 "                \"name\": \"dhcp-message\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp4\",\n"
 "                \"user-context\": {\n"
 "                    \"comment\": \"Set option value\"\n"
@@ -11364,6 +11402,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                        \"csv-format\": true,\n"
 "                                        \"data\": \"example.com\",\n"
 "                                        \"name\": \"domain-name\",\n"
+"                                        \"never-send\": false,\n"
 "                                        \"space\": \"dhcp4\",\n"
 "                                        \"user-context\": {\n"
 "                                            \"comment\": \"An option in a reservation\"\n"
@@ -11484,6 +11523,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": true,\n"
 "                        \"data\": \"192.0.3.95\",\n"
 "                        \"name\": \"name-servers\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp4\"\n"
 "                    },\n"
 "                    {\n"
@@ -11492,6 +11532,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": true,\n"
 "                        \"data\": \"11\",\n"
 "                        \"name\": \"default-ip-ttl\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp4\"\n"
 "                    }\n"
 "                ],\n"
@@ -11511,6 +11552,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": true,\n"
 "                        \"data\": \"192.0.3.15\",\n"
 "                        \"name\": \"name-servers\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp4\"\n"
 "                    },\n"
 "                    {\n"
@@ -11519,6 +11561,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": true,\n"
 "                        \"data\": \"32\",\n"
 "                        \"name\": \"default-ip-ttl\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp4\"\n"
 "                    }\n"
 "                ],\n"
index c0d485227b0fcd8770c776f6ec54b535da2ccde4..8e61eb1745826560ad849712164207944cba120d 100644 (file)
@@ -1327,6 +1327,116 @@ TEST_F(VendorOptsTest, vendorOptionsOROAndPersistentMultipleOptionDifferentVendo
                                       { 32768, 16384 },
                                       {},
                                       { DOCSIS3_V4_TFTP_SERVERS, 22 });
+// This test checks if cancelled options are actually never assigned.
+TEST_F(VendorOptsTest, vendorCancelledOptions) {
+    NakedDhcpv4Srv srv(0);
+
+    ConstElementPtr x;
+    string config = "{ \"interfaces-config\": {"
+        "    \"interfaces\": [ \"*\" ]"
+        "},"
+        "    \"option-def\": [ {"
+        "          \"space\": \"vendor-4491\","
+        "          \"name\": \"foo\","
+        "          \"code\": 100,"
+        "          \"type\": \"string\""
+        "        } ],"
+        "    \"option-data\": [ {"
+        "          \"name\": \"tftp-servers\","
+        "          \"space\": \"vendor-4491\","
+        "          \"code\": 2,"
+        "          \"data\": \"192.0.2.1, 192.0.2.2\","
+        "          \"csv-format\": true,"
+        "          \"always-send\": true"
+        "        },{"
+        "          \"space\": \"vendor-4491\","
+        "          \"code\": 100,"
+        "          \"csv-format\": true,"
+        "          \"data\": \"bar\""
+        "        } ],"
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"192.0.2.0/25\" } ],"
+        "    \"subnet\": \"192.0.2.0/24\", "
+        "    \"interface\": \"eth0\", "
+        "    \"option-data\": [ {"
+        "          \"name\": \"tftp-servers\","
+        "          \"space\": \"vendor-4491\","
+        "          \"code\": 2,"
+        "          \"never-send\": true"
+        "        } ]"
+        " } ]"
+        "}";
+
+    ConstElementPtr json;
+    ASSERT_NO_THROW(json = parseDHCP4(config));
+
+    EXPECT_NO_THROW(x = configureDhcp4Server(srv, json));
+    ASSERT_TRUE(x);
+    comment_ = parseAnswer(rcode_, x);
+    ASSERT_EQ(0, rcode_) << comment_->str();
+
+    CfgMgr::instance().commit();
+
+    boost::shared_ptr<Pkt4> dis(new Pkt4(DHCPDISCOVER, 1234));
+    // Set the giaddr and hops to non-zero address as if it was relayed.
+    dis->setGiaddr(IOAddress("192.0.2.1"));
+    dis->setHops(1);
+
+    OptionPtr clientid = generateClientId();
+    dis->addOption(clientid);
+    // Set interface. It is required by the server to generate server id.
+    dis->setIface("eth0");
+    dis->setIndex(ETH0_INDEX);
+
+    // Let's add a vendor-option (vendor-id=4491).
+    OptionPtr vendor(new OptionVendor(Option::V4, 4491));
+    dis->addOption(vendor);
+
+    // Pass it to the server and get an advertise
+    Pkt4Ptr offer = srv.processDiscover(dis);
+
+    // check if we get response at all
+    ASSERT_TRUE(offer);
+
+    // There should be no vendor option response.
+    EXPECT_FALSE(offer->getOption(DHO_VIVSO_SUBOPTIONS));
+
+    // Let's add a vendor-option (vendor-id=4491) with a single sub-option.
+    // That suboption has code 1 and is a docsis ORO option.
+    boost::shared_ptr<OptionUint8Array> vendor_oro(new OptionUint8Array(Option::V4,
+                                                                        DOCSIS3_V4_ORO));
+    vendor_oro->addValue(DOCSIS3_V4_TFTP_SERVERS); // Request option 2.
+    vendor->addOption(vendor_oro);
+
+    // Need to process DHCPDISCOVER again after requesting new option.
+    offer = srv.processDiscover(dis);
+    ASSERT_TRUE(offer);
+
+    // Again there should be no vendor option response.
+    EXPECT_FALSE(offer->getOption(DHO_VIVSO_SUBOPTIONS));
+
+    // Request option 100.
+    vendor_oro->addValue(100);
+
+    // Try again.
+    offer = srv.processDiscover(dis);
+    ASSERT_TRUE(offer);
+
+    // Check if there is a vendor option response
+    OptionPtr tmp = offer->getOption(DHO_VIVSO_SUBOPTIONS);
+    ASSERT_TRUE(tmp);
+
+    // The response should be OptionVendor object
+    boost::shared_ptr<OptionVendor> vendor_resp =
+        boost::dynamic_pointer_cast<OptionVendor>(tmp);
+    ASSERT_TRUE(vendor_resp);
+
+    // No tftp-servers.
+    EXPECT_FALSE(vendor_resp->getOption(DOCSIS3_V4_TFTP_SERVERS));
+
+    // But an option 100.
+    EXPECT_EQ(1, vendor_resp->getOptions().size());
+    EXPECT_TRUE(vendor_resp->getOption(100));
 }
 
 // Test checks whether it is possible to use option definitions defined in
index 3d27fe151caf1cb694572471b580cf01ecfa1cf0..d9064e5d84b89f0f38c1860800ca45e2e67fae5e 100644 (file)
@@ -1192,6 +1192,15 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     }
 }
 
+\"never-send\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::OPTION_DATA:
+        return isc::dhcp::Dhcp6Parser::make_NEVER_SEND(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("never-send", driver.loc_);
+    }
+}
+
 \"pools\" {
     switch(driver.ctx_) {
     case isc::dhcp::Parser6Context::SUBNET6:
index 115980c65c967d76719e5755223a150036d84fd0..759f57afe0ada59b3987cc591ce417dace41fd81 100644 (file)
@@ -128,6 +128,7 @@ using namespace std;
   SPACE "space"
   CSV_FORMAT "csv-format"
   ALWAYS_SEND "always-send"
+  NEVER_SEND "never-send"
   RECORD_TYPES "record-types"
   ENCAPSULATE "encapsulate"
   ARRAY "array"
@@ -1988,6 +1989,7 @@ option_data_param: option_data_name
                  | option_data_space
                  | option_data_csv_format
                  | option_data_always_send
+                 | option_data_never_send
                  | user_context
                  | comment
                  | unknown_map_entry
@@ -2020,6 +2022,12 @@ option_data_always_send: ALWAYS_SEND COLON BOOLEAN {
     ctx.stack_.back()->set("always-send", persist);
 };
 
+option_data_never_send: NEVER_SEND COLON BOOLEAN {
+    ctx.unique("never-send", ctx.loc2pos(@1));
+    ElementPtr persist(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("never-send", persist);
+};
+
 // ---- pools ------------------------------------
 
 // This defines the "pools": [ ... ] entry that may appear in subnet6.
index 9709f3bc6d40a5044829e5fe49f7d932a6dcb293..c250cef3fa087ab077d1053cc6d8a66547e79f45 100644 (file)
@@ -1492,28 +1492,46 @@ Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
         }
     }
 
-    // Iterate on the configured option list to add persistent options
+    set<uint16_t> cancelled_opts;
+
+    // Iterate on the configured option list to add persistent and
+    // cancelled options.
     for (auto const& copts : co_list) {
         const OptionContainerPtr& opts = copts->getAll(DHCP6_OPTION_SPACE);
         if (!opts) {
             continue;
         }
-        // Get persistent options
-        const OptionContainerPersistIndex& idx = opts->get<2>();
-        const OptionContainerPersistRange& range = idx.equal_range(true);
-        for (OptionContainerPersistIndex::const_iterator desc = range.first;
-             desc != range.second; ++desc) {
-            // Add the persistent option code to requested options
+        // Get persistent options.
+        const OptionContainerPersistIndex& pidx = opts->get<2>();
+        const OptionContainerPersistRange& prange = pidx.equal_range(true);
+        for (OptionContainerPersistIndex::const_iterator desc = prange.first;
+             desc != prange.second; ++desc) {
+            // Add the persistent option code to requested options.
             if (desc->option_) {
                 uint16_t code = desc->option_->getType();
                 static_cast<void>(requested_opts.insert(code));
             }
         }
+        // Get cancelled options.
+        const OptionContainerCancelIndex& cidx = opts->get<5>();
+        const OptionContainerCancelRange& crange = cidx.equal_range(true);
+        for (OptionContainerCancelIndex::const_iterator desc = crange.first;
+             desc != crange.second; ++desc) {
+            // Add the cancelled option code to the cancelled options.
+            if (desc->option_) {
+                uint16_t code = desc->option_->getType();
+                static_cast<void>(cancelled_opts.insert(code));
+            }
+        }
     }
 
     // For each requested option code get the first instance of the option
     // to be returned to the client.
     for (uint16_t opt : requested_opts) {
+        // Skip if cancelled.
+        if (cancelled_opts.count(opt) > 0) {
+            continue;
+        }
         // Add nothing when it is already there.
         // Skip special cases: D6O_VENDOR_OPTS
         if (opt == D6O_VENDOR_OPTS) {
@@ -1534,7 +1552,10 @@ Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
 
     // Special cases for vendor class and options which are identified
     // by the code/type and the vendor/enterprise id vs. the code/type only.
-    if (requested_opts.count(D6O_VENDOR_CLASS) > 0) {
+    if ((requested_opts.count(D6O_VENDOR_CLASS) > 0) &&
+        (cancelled_opts.count(D6O_VENDOR_CLASS) == 0)) {
+        // Keep vendor ids which are already in the response to insert
+        // D6O_VENDOR_CLASS options at most once per vendor.
         set<uint32_t> vendor_ids;
         // Get what already exists in the response.
         for (auto opt : answer->getOptions(D6O_VENDOR_CLASS)) {
@@ -1569,7 +1590,10 @@ Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
         }
     }
 
-    if (requested_opts.count(D6O_VENDOR_OPTS) > 0) {
+    if ((requested_opts.count(D6O_VENDOR_OPTS) > 0) &&
+        (cancelled_opts.count(D6O_VENDOR_OPTS) == 0)) {
+        // Keep vendor ids which are already in the response to insert
+        // D6O_VENDOR_OPTS options at most once per vendor.
         set<uint32_t> vendor_ids;
         // Get what already exists in the response.
         for (auto opt : answer->getOptions(D6O_VENDOR_OPTS)) {
@@ -1694,18 +1718,21 @@ Dhcpv6Srv::appendRequestedVendorOptions(const Pkt6Ptr& question,
         }
     }
 
-    // Iterate on the configured option list to add persistent options
+    map<uint32_t, set<uint16_t> > cancelled_opts;
+
+    // Iterate on the configured option list to add persistent and
+    // cancelled options.
     for (uint32_t vendor_id : vendor_ids) {
         for (auto const& copts : co_list) {
             const OptionContainerPtr& opts = copts->getAll(vendor_id);
             if (!opts) {
                 continue;
             }
-            // Get persistent options
-            const OptionContainerPersistIndex& idx = opts->get<2>();
-            const OptionContainerPersistRange& range = idx.equal_range(true);
-            for (OptionContainerPersistIndex::const_iterator desc = range.first;
-                 desc != range.second; ++desc) {
+            // Get persistent options.
+            const OptionContainerPersistIndex& pidx = opts->get<2>();
+            const OptionContainerPersistRange& prange = pidx.equal_range(true);
+            for (OptionContainerPersistIndex::const_iterator desc = prange.first;
+                 desc != prange.second; ++desc) {
                 if (!desc->option_) {
                     continue;
                 }
@@ -1713,6 +1740,18 @@ Dhcpv6Srv::appendRequestedVendorOptions(const Pkt6Ptr& question,
                 uint16_t code = desc->option_->getType();
                 static_cast<void>(requested_opts[vendor_id].insert(code));
             }
+            // Get cancelled options.
+            const OptionContainerCancelIndex& cidx = opts->get<5>();
+            const OptionContainerCancelRange& crange = cidx.equal_range(true);
+            for (OptionContainerCancelIndex::const_iterator desc = crange.first;
+                 desc != crange.second; ++desc) {
+                if (!desc->option_) {
+                    continue;
+                }
+                // Add the cancelled option code to cancelled options
+                uint16_t code = desc->option_->getType();
+                static_cast<void>(cancelled_opts[vendor_id].insert(code));
+            }
         }
 
         // If there is nothing to add don't do anything with this vendor.
@@ -1737,6 +1776,9 @@ Dhcpv6Srv::appendRequestedVendorOptions(const Pkt6Ptr& question,
         bool added = false;
 
         for (uint16_t opt : requested_opts[vendor_id]) {
+            if (cancelled_opts[vendor_id].count(opt) > 0) {
+                continue;
+            }
             if (!vendor_rsp->getOption(opt)) {
                 for (auto const& copts : co_list) {
                     OptionDescriptor desc = copts->get(vendor_id, opt);
index d22a67f9f434abe7b43406d1af6d3bfbe7de2ed1..2116c08be710a2d4f7a6cd0d4f66470c29bd68d9 100644 (file)
@@ -1141,7 +1141,8 @@ TEST_F(ClassifyTest, classGlobalPersistency) {
         "\"option-data\": ["
         "    {    \"name\": \"ipv6-forwarding\", "
         "         \"data\": \"false\", "
-        "         \"always-send\": true } ], "
+        "         \"always-send\": true, "
+        "         \"never-send\": false } ], "
         "\"subnet6\": [ "
         "{   \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], "
         "    \"subnet\": \"2001:db8:1::/48\", "
@@ -1149,7 +1150,8 @@ TEST_F(ClassifyTest, classGlobalPersistency) {
         "    \"option-data\": ["
         "        {    \"name\": \"ipv6-forwarding\", "
         "             \"data\": \"false\", "
-        "             \"always-send\": false } ] } ] }";
+        "             \"always-send\": false, "
+        "             \"never-send\": false } ] } ] }";
     ASSERT_NO_THROW(configure(config));
 
     // Create a packet with enough to select the subnet and go through
@@ -1182,6 +1184,70 @@ TEST_F(ClassifyTest, classGlobalPersistency) {
     EXPECT_EQ(0, opt->getUint8());
 }
 
+// Checks class never-send options have the priority over everything else.
+TEST_F(ClassifyTest, classNeverSend) {
+    IfaceMgrTestConfig test_config(true);
+
+    NakedDhcpv6Srv srv(0);
+
+    // Subnet sets an ipv6-forwarding option in the response.
+    // The router class matches incoming packets with foo in a host-name
+    // option (code 1234) and sets an ipv6-forwarding option in the response.
+    // Note the cancellation flag follows a "OR" semantic so to set
+    // it to false (or to leave the default) has no effect.
+    std::string config = "{ \"interfaces-config\": {"
+        "    \"interfaces\": [ \"*\" ] }, "
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"valid-lifetime\": 4000, "
+        "\"option-def\": [ "
+        "{   \"name\": \"host-name\","
+        "    \"code\": 1234,"
+        "    \"type\": \"string\" },"
+        "{   \"name\": \"ipv6-forwarding\","
+        "    \"code\": 2345,"
+        "    \"type\": \"boolean\" }],"
+        "\"option-data\": ["
+        "    {    \"name\": \"ipv6-forwarding\", "
+        "         \"data\": \"false\", "
+        "         \"always-send\": true, "
+        "         \"never-send\": false } ], "
+        "\"subnet6\": [ "
+        "{   \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], "
+        "    \"subnet\": \"2001:db8:1::/48\", "
+        "    \"interface\": \"eth1\", "
+        "    \"option-data\": ["
+        "        {    \"name\": \"ipv6-forwarding\", "
+        "             \"always-send\": false, "
+        "             \"never-send\": true } ] } ] }";
+    ASSERT_NO_THROW(configure(config));
+
+    // Create a packet with enough to select the subnet and go through
+    // the SOLICIT processing
+    Pkt6Ptr query = createSolicit();
+
+    // Do not add an ORO.
+    OptionPtr oro = query->getOption(D6O_ORO);
+    EXPECT_FALSE(oro);
+
+    // Create and add a host-name option to the query
+    OptionStringPtr hostname(new OptionString(Option::V6, 1234, "foo"));
+    ASSERT_TRUE(hostname);
+    query->addOption(hostname);
+
+    // Process the query
+    AllocEngine::ClientContext6 ctx;
+    bool drop = !srv.earlyGHRLookup(query, ctx);
+    ASSERT_FALSE(drop);
+    srv.initContext(query, ctx,  drop);
+    ASSERT_FALSE(drop);
+    Pkt6Ptr response = srv.processSolicit(ctx);
+
+    // Processing should not add an ip-forwarding option
+    EXPECT_FALSE(response->getOption(2345));
+}
+
 // Checks if the client-class field is indeed used for subnet selection.
 // Note that packet classification is already checked in ClassifyTest
 // .*Classification above.
index ce2842944eb6912815e4c7a3238044d3e7ea9f42..ba16a904951ec26bec059bb8b2d43f1a80b9b062 100644 (file)
@@ -325,14 +325,15 @@ TEST_F(Dhcp6CBTest, mergeOptions) {
     // Add solmax-rt to the first backend.
     opt.reset(new OptionDescriptor(
               createOption<OptionString>(Option::V6, D6O_BOOTFILE_URL,
-                                         true, false, "updated-boot-file")));
+                                         true, false, false,
+                                         "updated-boot-file")));
     opt->space_name_ = DHCP6_OPTION_SPACE;
     db1_->createUpdateOption6(ServerSelector::ALL(), opt);
 
     // Add solmax-rt to the second backend.
     opt.reset(new OptionDescriptor(
               createOption<OptionUint32>(Option::V6, D6O_SOL_MAX_RT,
-                                         false, true, 700)));
+                                         false, false, true, 700)));
     opt->space_name_ = DHCP6_OPTION_SPACE;
     db2_->createUpdateOption6(ServerSelector::ALL(), opt);
 
index 4dab6a13b7e63afd3a1caa650ad9c611877cd10b..51344d0c38e50189e54de3456920ea7e955f7eb8 100644 (file)
@@ -638,7 +638,7 @@ public:
             ADD_FAILURE() << "A subnet for the specified address "
                           << subnet_address
                           << " does not exist in Config Manager";
-            return (OptionDescriptor(false));
+            return (OptionDescriptor(false, false));
         }
         OptionContainerPtr options =
             subnet->getCfgOption()->getAll(DHCP6_OPTION_SPACE);
@@ -664,7 +664,7 @@ public:
                           << subnet_address.toText() << "'. Expected "
                 " at most one option";
         } else if (std::distance(range.first, range.second) == 0) {
-            return (OptionDescriptor(OptionPtr(), false));
+            return (OptionDescriptor(OptionPtr(), false, false));
         }
 
         return (*range.first);
index ad9bcf001724cb525b55a9bf3c9581d5d5528fa6..2c63c5623c647508b25e5c3d26902e613d708a43 100644 (file)
@@ -123,6 +123,7 @@ const char* CONFIGS[] = {
     "    \"renew-timer\": 1000, "
     "    \"valid-lifetime\": 4000, "
     "    \"subnet6\": [ {"
+    "       \"interface\": \"eth0\", "
     "       \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], "
     "       \"subnet\": \"2001:db8:1::/48\""
     "    } ], "
@@ -140,6 +141,38 @@ const char* CONFIGS[] = {
     "}",
 
     // Configuration 3:
+    // - a single subnet with one option cancelled with never-send.
+    // - two global options (one enforced with always-send)
+    "{"
+    "    \"interfaces-config\": { \"interfaces\": [ \"*\" ] }, "
+    "    \"preferred-lifetime\": 3000, "
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"valid-lifetime\": 4000, "
+    "    \"subnet6\": [ {"
+    "       \"interface\": \"eth0\", "
+    "       \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], "
+    "       \"subnet\": \"2001:db8:1::/48\", "
+    "       \"option-data\": ["
+    "       {"
+    "           \"name\": \"subscriber-id\", "
+    "           \"never-send\": true"
+    "       } ]"
+    "    } ], "
+    "    \"option-data\": ["
+    "    {"
+    "        \"name\": \"dns-servers\", "
+    "        \"data\": \"2001:db8:1234:FFFF::1\""
+    "    }, "
+    "    {"
+    "        \"name\": \"subscriber-id\", "
+    "         \"data\": \"1234\", "
+    "         \"always-send\": true"
+    "    }"
+    "    ]"
+    "}",
+
+    // Configuration 4:
     // - one subnet with one address pool and one prefix pool
     // - user-contexts defined in subnet and each pool
     "{"
@@ -2834,7 +2867,7 @@ TEST_F(Dhcpv6SrvTest, relaySourcePort) {
     EXPECT_TRUE(adv->getRelayOption(D6O_RELAY_SOURCE_PORT, 0));
 }
 
-// Checks effect of persistency (aka always-true) flag on the ORO
+// Checks effect of persistency (aka always-send) flag on the ORO
 TEST_F(Dhcpv6SrvTest, prlPersistency) {
     IfaceMgrTestConfig test_config(true);
 
@@ -2917,6 +2950,87 @@ TEST_F(Dhcpv6SrvTest, prlPersistency) {
     ASSERT_FALSE(response->getOption(D6O_SNTP_SERVERS));
 }
 
+// Checks effect of cancellation (aka never-send) flag.
+TEST_F(Dhcpv6SrvTest, neverSend) {
+    IfaceMgrTestConfig test_config(true);
+
+    ASSERT_NO_THROW(configure(CONFIGS[3]));
+
+    // Create a packet with enough to select the subnet and go through
+    // the SOLICIT processing
+    Pkt6Ptr sol(new Pkt6(DHCPV6_SOLICIT, 1234));
+    sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface("eth0");
+    sol->setIndex(ETH0_INDEX);
+    sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
+    OptionPtr clientid = generateClientId();
+    sol->addOption(clientid);
+
+    // Create and add an ORO for another option
+    OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6, D6O_ORO));
+    ASSERT_TRUE(oro);
+    oro->addValue(D6O_SNTP_SERVERS);
+    sol->addOption(oro);
+
+    // Let the server process it and generate a response.
+    AllocEngine::ClientContext6 ctx;
+    bool drop = !srv_.earlyGHRLookup(sol, ctx);
+    ASSERT_FALSE(drop);
+    srv_.initContext(sol, ctx, drop);
+    ASSERT_FALSE(drop);
+    Pkt6Ptr response = srv_.processSolicit(ctx);
+
+    // The server should not add a subscriber-id option
+    ASSERT_FALSE(response->getOption(D6O_SUBSCRIBER_ID));
+    // And no dns-servers
+    ASSERT_FALSE(response->getOption(D6O_NAME_SERVERS));
+    // Nor a sntp-servers
+    ASSERT_FALSE(response->getOption(D6O_SNTP_SERVERS));
+
+    // Reset ORO adding dns-servers
+    sol->delOption(D6O_ORO);
+    oro->addValue(D6O_NAME_SERVERS);
+    sol->addOption(oro);
+
+    // Let the server process it again. This time the name-servers
+    // option should be present.
+    AllocEngine::ClientContext6 ctx2;
+    drop = !srv_.earlyGHRLookup(sol, ctx2);
+    ASSERT_FALSE(drop);
+    srv_.initContext(sol, ctx2, drop);
+    ASSERT_FALSE(drop);
+    response = srv_.processSolicit(ctx2);
+
+    // Processing should not add a subscriber-id option
+    ASSERT_FALSE(response->getOption(D6O_SUBSCRIBER_ID));
+    // But now a dns-servers
+    ASSERT_TRUE(response->getOption(D6O_NAME_SERVERS));
+    // And still no sntp-servers
+    ASSERT_FALSE(response->getOption(D6O_SNTP_SERVERS));
+
+    // Reset ORO adding subscriber-id
+    sol->delOption(D6O_ORO);
+    OptionUint16ArrayPtr oro2(new OptionUint16Array(Option::V6, D6O_ORO));
+    ASSERT_TRUE(oro2);
+    oro2->addValue(D6O_SUBSCRIBER_ID);
+    sol->addOption(oro2);
+
+    // Let the server process it again.
+    AllocEngine::ClientContext6 ctx3;
+    drop = !srv_.earlyGHRLookup(sol, ctx3);
+    ASSERT_FALSE(drop);
+    srv_.initContext(sol, ctx3, drop);
+    ASSERT_FALSE(drop);
+    response = srv_.processSolicit(ctx3);
+
+    // The subscriber-id option should still not be present.
+    ASSERT_FALSE(response->getOption(D6O_SUBSCRIBER_ID));
+    // And no dns-servers
+    ASSERT_FALSE(response->getOption(D6O_NAME_SERVERS));
+    // Nor a sntp-servers
+    ASSERT_FALSE(response->getOption(D6O_SNTP_SERVERS));
+}
+
 // Checks if server is able to handle a relayed traffic from DOCSIS3.0 modems
 // @todo Uncomment this test as part of #3180 work.
 // Kea code currently fails to handle docsis traffic.
@@ -3486,7 +3600,7 @@ TEST_F(Dhcpv6SrvTest, userContext) {
 
     // This config has one subnet with user-context with one
     // pool (also with context). Make sure the configuration could be accepted.
-    EXPECT_NO_THROW(configure(CONFIGS[3]));
+    EXPECT_NO_THROW(configure(CONFIGS[4]));
 
     // Now make sure the data was not lost.
     ConstSrvConfigPtr cfg = CfgMgr::instance().getCurrentCfg();
index 842805f1d7e71304541bab15a5ef4b60fcce15e5..72ac7b89a3d193f7032ee21ced88e5db9a5e1dd5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2017-2023 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2022 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -20,7 +20,6 @@
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp6/tests/get_config_unittest.h>
 #include <testutils/gtest_utils.h>
-#include <testutils/test_to_element.h>
 
 #include <boost/algorithm/string.hpp>
 #include <gtest/gtest.h>
@@ -4675,6 +4674,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": false,\n"
 "                \"data\": \"ABCDEF0105\",\n"
 "                \"name\": \"subscriber-id\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp6\"\n"
 "            },\n"
 "            {\n"
@@ -4683,6 +4683,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"01\",\n"
 "                \"name\": \"preference\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp6\"\n"
 "            }\n"
 "        ],\n"
@@ -4852,6 +4853,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": false,\n"
 "                        \"data\": \"ABCDEF0105\",\n"
 "                        \"name\": \"subscriber-id\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp6\"\n"
 "                    },\n"
 "                    {\n"
@@ -4860,6 +4862,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": true,\n"
 "                        \"data\": \"01\",\n"
 "                        \"name\": \"preference\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp6\"\n"
 "                    }\n"
 "                ],\n"
@@ -4953,6 +4956,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": false,\n"
 "                \"data\": \"ABCDEF0105\",\n"
 "                \"name\": \"subscriber-id\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp6\"\n"
 "            },\n"
 "            {\n"
@@ -4961,6 +4965,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"1234\",\n"
 "                \"name\": \"foo\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"isc\"\n"
 "            }\n"
 "        ],\n"
@@ -5102,6 +5107,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"1234\",\n"
 "                \"name\": \"foo\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"isc\"\n"
 "            },\n"
 "            {\n"
@@ -5110,6 +5116,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"192.168.2.1\",\n"
 "                \"name\": \"foo2\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"isc\"\n"
 "            }\n"
 "        ],\n"
@@ -5228,6 +5235,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"11\",\n"
 "                \"name\": \"base-option\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp6\"\n"
 "            },\n"
 "            {\n"
@@ -5236,6 +5244,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"1234\",\n"
 "                \"name\": \"foo\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"isc\"\n"
 "            },\n"
 "            {\n"
@@ -5244,6 +5253,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"192.168.2.1\",\n"
 "                \"name\": \"foo2\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"isc\"\n"
 "            }\n"
 "        ],\n"
@@ -5441,6 +5451,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": false,\n"
 "                        \"data\": \"0102030405060708090A\",\n"
 "                        \"name\": \"subscriber-id\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp6\"\n"
 "                    }\n"
 "                ],\n"
@@ -5481,6 +5492,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": false,\n"
 "                        \"data\": \"FFFEFDFCFB\",\n"
 "                        \"name\": \"user-class\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp6\"\n"
 "                    }\n"
 "                ],\n"
@@ -5617,6 +5629,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": false,\n"
 "                                \"data\": \"112233445566\",\n"
 "                                \"name\": \"subscriber-id\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp6\"\n"
 "                            }\n"
 "                        ],\n"
@@ -5632,6 +5645,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": false,\n"
 "                                \"data\": \"AABBCCDDEE\",\n"
 "                                \"name\": \"user-class\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp6\"\n"
 "                            }\n"
 "                        ],\n"
@@ -5648,6 +5662,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": false,\n"
 "                                \"data\": \"0102030405060708090A\",\n"
 "                                \"name\": \"subscriber-id\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp6\"\n"
 "                            }\n"
 "                        ],\n"
@@ -5661,6 +5676,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": false,\n"
 "                                \"data\": \"FFFEFDFCFB\",\n"
 "                                \"name\": \"user-class\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp6\"\n"
 "                            }\n"
 "                        ],\n"
@@ -5748,6 +5764,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"code\": 100,\n"
 "                \"csv-format\": false,\n"
 "                \"data\": \"1234\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"vendor-1234\"\n"
 "            },\n"
 "            {\n"
@@ -5755,6 +5772,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"code\": 100,\n"
 "                \"csv-format\": false,\n"
 "                \"data\": \"ABCDEF0105\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"vendor-4491\"\n"
 "            }\n"
 "        ],\n"
@@ -5886,6 +5904,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": true,\n"
 "                \"data\": \"this is a string vendor-opt\",\n"
 "                \"name\": \"foo\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"vendor-4491\"\n"
 "            }\n"
 "        ],\n"
@@ -7403,6 +7422,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"2001:db8:2::abbc\",\n"
 "                                \"name\": \"dns-servers\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp6\"\n"
 "                            },\n"
 "                            {\n"
@@ -7411,6 +7431,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"25\",\n"
 "                                \"name\": \"preference\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp6\"\n"
 "                            }\n"
 "                        ],\n"
@@ -7428,6 +7449,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"2001:db8:2::1111\",\n"
 "                                \"name\": \"dns-servers\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp6\"\n"
 "                            },\n"
 "                            {\n"
@@ -7436,6 +7458,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"11\",\n"
 "                                \"name\": \"preference\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp6\"\n"
 "                            }\n"
 "                        ],\n"
@@ -7488,6 +7511,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"2001:db8:3::3333\",\n"
 "                                \"name\": \"dns-servers\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp6\"\n"
 "                            },\n"
 "                            {\n"
@@ -7496,6 +7520,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"33\",\n"
 "                                \"name\": \"preference\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"dhcp6\"\n"
 "                            }\n"
 "                        ],\n"
@@ -7641,6 +7666,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                \"csv-format\": true,\n"
 "                                \"data\": \"11\",\n"
 "                                \"name\": \"foo\",\n"
+"                                \"never-send\": false,\n"
 "                                \"space\": \"isc\"\n"
 "                            }\n"
 "                        ],\n"
@@ -9978,6 +10004,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"csv-format\": false,\n"
 "                \"data\": \"ABCDEF0105\",\n"
 "                \"name\": \"subscriber-id\",\n"
+"                \"never-send\": false,\n"
 "                \"space\": \"dhcp6\",\n"
 "                \"user-context\": {\n"
 "                    \"comment\": \"Set option value\"\n"
@@ -10087,6 +10114,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                                        \"csv-format\": true,\n"
 "                                        \"data\": \"example.com\",\n"
 "                                        \"name\": \"domain-search\",\n"
+"                                        \"never-send\": false,\n"
 "                                        \"space\": \"dhcp6\",\n"
 "                                        \"user-context\": {\n"
 "                                            \"comment\": \"An option in a reservation\"\n"
@@ -10205,6 +10233,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": true,\n"
 "                        \"data\": \"2001:db8:2::abbc\",\n"
 "                        \"name\": \"dns-servers\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp6\"\n"
 "                    },\n"
 "                    {\n"
@@ -10213,6 +10242,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": true,\n"
 "                        \"data\": \"25\",\n"
 "                        \"name\": \"preference\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp6\"\n"
 "                    }\n"
 "                ],\n"
@@ -10230,6 +10260,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": true,\n"
 "                        \"data\": \"2001:db8:2::1111\",\n"
 "                        \"name\": \"dns-servers\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp6\"\n"
 "                    },\n"
 "                    {\n"
@@ -10238,6 +10269,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"csv-format\": true,\n"
 "                        \"data\": \"11\",\n"
 "                        \"name\": \"preference\",\n"
+"                        \"never-send\": false,\n"
 "                        \"space\": \"dhcp6\"\n"
 "                    }\n"
 "                ],\n"
index d96dbcbe3d9b0be647c15f7e141d9209b46cee08..f179e2ff0042c66c15f5fc70e86476eccb9470c3 100644 (file)
@@ -1311,6 +1311,120 @@ TEST_F(VendorOptsTest, vendorOptionsOROAndPersistentMultipleOptionDifferentVendo
                                       { DOCSIS3_V6_CONFIG_FILE, 12 });
 }
 
+// This test checks if cancellation (aka never-send) flag unconditionally
+// makes the server to never add the specified option.
+TEST_F(VendorOptsTest, vendorNeverSend) {
+    string config = "{ \"interfaces-config\": {"
+        "  \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "    \"option-def\": [ {"
+        "        \"name\": \"config-file\","
+        "        \"code\": 33,"
+        "        \"type\": \"string\","
+        "        \"space\": \"vendor-4491\""
+        "     },"
+        "     {"
+        "        \"name\": \"vendor-name\","
+        "        \"code\": 10,"
+        "        \"type\": \"string\","
+        "        \"space\": \"vendor-4491\""
+        "     } ],"
+        "    \"option-data\": [ {"
+        "          \"name\": \"config-file\","
+        "          \"space\": \"vendor-4491\","
+        "          \"data\": \"normal_erouter_v6.cm\","
+        "          \"always-send\": true"
+        "     },"
+        "     {"
+        "          \"name\": \"vendor-name\","
+        "          \"space\": \"vendor-4491\","
+        "          \"data\": \"ISC\""
+        "        }],"
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+        "    \"subnet\": \"2001:db8:1::/48\", "
+        "    \"renew-timer\": 1000, "
+        "    \"rebind-timer\": 1000, "
+        "    \"preferred-lifetime\": 3000,"
+        "    \"valid-lifetime\": 4000,"
+        "    \"interface-id\": \"\","
+        "    \"interface\": \"eth0\","
+        "    \"option-data\": [ {"
+        "           \"name\": \"config-file\","
+        "           \"space\": \"vendor-4491\","
+        "           \"never-send\": true"
+        "     } ]"
+        " } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    ASSERT_NO_THROW(configure(config));
+
+    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+    sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface("eth0");
+    sol->setIndex(ETH0_INDEX);
+    sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
+    OptionPtr clientid = generateClientId();
+    sol->addOption(clientid);
+
+    // Let's add a vendor-option (vendor-id=4491).
+    OptionPtr vendor(new OptionVendor(Option::V6, 4491));
+    sol->addOption(vendor);
+
+    // Pass it to the server and get an advertise
+    AllocEngine::ClientContext6 ctx;
+    bool drop = !srv_.earlyGHRLookup(sol, ctx);
+    ASSERT_FALSE(drop);
+    srv_.initContext(sol, ctx, drop);
+    ASSERT_FALSE(drop);
+    Pkt6Ptr adv = srv_.processSolicit(ctx);
+
+    // check if we get response at all
+    ASSERT_TRUE(adv);
+
+    // There is no vendor option response.
+    EXPECT_FALSE(adv->getOption(D6O_VENDOR_OPTS));
+
+    // Add again an ORO but requesting both 10 and 33.
+    sol->delOption(D6O_VENDOR_OPTS);
+    boost::shared_ptr<OptionUint16Array> vendor_oro2(new OptionUint16Array(Option::V6,
+                                                                          DOCSIS3_V6_ORO));
+    vendor_oro2->addValue(DOCSIS3_V6_VENDOR_NAME); // Request option 10
+    vendor_oro2->addValue(DOCSIS3_V6_CONFIG_FILE); // Request option 33
+    OptionPtr vendor3(new OptionVendor(Option::V6, 4491));
+    vendor3->addOption(vendor_oro2);
+    sol->addOption(vendor3);
+
+    // Need to process SOLICIT again after requesting new option.
+    AllocEngine::ClientContext6 ctx3;
+    drop = !srv_.earlyGHRLookup(sol, ctx3);
+    ASSERT_FALSE(drop);
+    srv_.initContext(sol, ctx3, drop);
+    ASSERT_FALSE(drop);
+    adv = srv_.processSolicit(ctx3);
+    ASSERT_TRUE(adv);
+
+    // Check if there is vendor option response
+    OptionPtr tmp = adv->getOption(D6O_VENDOR_OPTS);
+    ASSERT_TRUE(tmp);
+
+    // The response should be OptionVendor object
+    boost::shared_ptr<OptionVendor> vendor_resp =
+        boost::dynamic_pointer_cast<OptionVendor>(tmp);
+    ASSERT_TRUE(vendor_resp);
+
+    // Still no config-file (33) option.
+    EXPECT_FALSE(vendor_resp->getOption(33));
+
+    // But the vendor option response is not empty.
+    const OptionCollection& opts = vendor_resp->getOptions();
+    ASSERT_EQ(1, opts.size());
+    EXPECT_TRUE(vendor_resp->getOption(10));
+}
+
 // Test checks whether it is possible to use option definitions defined in
 // src/lib/dhcp/docsis3_option_defs.h.
 TEST_F(VendorOptsTest, vendorOptionsDocsisDefinitions) {
index 307a982becb2f5a5bf06f184d892d080c5b480e0..c596bb7dba917fb084f56f2d87dd600dc88c34f8 100644 (file)
@@ -316,6 +316,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pool option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pool option: space
             MySqlBinding::createInteger<uint8_t>(), // pool option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // pool option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // pool option: dhcp4_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // pool option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool option: user_context
@@ -328,6 +329,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space
             MySqlBinding::createInteger<uint8_t>(), // option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // option: dhcp4_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context
@@ -403,11 +405,11 @@ public:
                 auto rebind_timer = createTriplet(out_bindings[11]);
 
                 // valid_lifetime at 19.
-                // min_valid_lifetime at 53.
-                // max_valid_lifetime at 54.
+                // min_valid_lifetime at 55.
+                // max_valid_lifetime at 56.
                 auto valid_lifetime = createTriplet(out_bindings[19],
-                                                    out_bindings[53],
-                                                    out_bindings[54]);
+                                                    out_bindings[55],
+                                                    out_bindings[56]);
 
                 // Create subnet with basic settings.
                 last_subnet = Subnet4::create(prefix_pair.first, prefix_pair.second,
@@ -531,86 +533,86 @@ public:
 
                 // valid_lifetime at 19.
 
-                // pool and option from 20 to 48.
+                // pool and option from 20 to 50.
 
-                // calculate_tee_times at 49.
-                if (!out_bindings[49]->amNull()) {
-                    last_subnet->setCalculateTeeTimes(out_bindings[49]->getBool());
+                // calculate_tee_times at 51.
+                if (!out_bindings[51]->amNull()) {
+                    last_subnet->setCalculateTeeTimes(out_bindings[51]->getBool());
                 }
 
-                // t1_percent at 50.
-                if (!out_bindings[50]->amNull()) {
-                    last_subnet->setT1Percent(out_bindings[50]->getFloat());
+                // t1_percent at 52.
+                if (!out_bindings[52]->amNull()) {
+                    last_subnet->setT1Percent(out_bindings[52]->getFloat());
                 }
 
-                // t2_percent at 51.
-                if (!out_bindings[51]->amNull()) {
-                    last_subnet->setT2Percent(out_bindings[51]->getFloat());
+                // t2_percent at 53.
+                if (!out_bindings[53]->amNull()) {
+                    last_subnet->setT2Percent(out_bindings[53]->getFloat());
                 }
 
-                // authoritative at 52.
-                if (!out_bindings[52]->amNull()) {
-                    last_subnet->setAuthoritative(out_bindings[52]->getBool());
+                // authoritative at 54.
+                if (!out_bindings[54]->amNull()) {
+                    last_subnet->setAuthoritative(out_bindings[54]->getBool());
                 }
 
-                // min_valid_lifetime at 53.
-                // max_valid_lifetime at 54.
+                // min_valid_lifetime at 55.
+                // max_valid_lifetime at 56.
 
                 // pool client_class, require_client_classes and user_context
-                // from 55 to 57.
-
-                // ddns_send_updates at 58.
-                if (!out_bindings[58]->amNull()) {
-                    last_subnet->setDdnsSendUpdates(out_bindings[58]->getBool());
-                }
+                // from 57 to 59.
 
-                // ddns_override_no_update at 59.
-                if (!out_bindings[59]->amNull()) {
-                    last_subnet->setDdnsOverrideNoUpdate(out_bindings[59]->getBool());
-                }
-
-                // ddns_override_client_update at 60.
+                // ddns_send_updates at 60.
                 if (!out_bindings[60]->amNull()) {
-                    last_subnet->setDdnsOverrideClientUpdate(out_bindings[60]->getBool());
+                    last_subnet->setDdnsSendUpdates(out_bindings[60]->getBool());
                 }
 
-                // ddns_replace_client_name at 61.
+                // ddns_override_no_update at 61.
                 if (!out_bindings[61]->amNull()) {
-                    last_subnet->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode>
-                        (out_bindings[61]->getInteger<uint8_t>()));
+                    last_subnet->setDdnsOverrideNoUpdate(out_bindings[61]->getBool());
                 }
 
-                // ddns_generated_prefix at 62.
+                // ddns_override_client_update at 62.
                 if (!out_bindings[62]->amNull()) {
-                    last_subnet->setDdnsGeneratedPrefix(out_bindings[62]->getString());
+                    last_subnet->setDdnsOverrideClientUpdate(out_bindings[62]->getBool());
                 }
 
-                // ddns_qualifying_suffix at 63.
+                // ddns_replace_client_name at 63.
                 if (!out_bindings[63]->amNull()) {
-                    last_subnet->setDdnsQualifyingSuffix(out_bindings[63]->getString());
+                    last_subnet->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode>
+                        (out_bindings[63]->getInteger<uint8_t>()));
                 }
 
-                // reservations_in_subnet at 64.
+                // ddns_generated_prefix at 64.
                 if (!out_bindings[64]->amNull()) {
-                    last_subnet->setReservationsInSubnet(out_bindings[64]->getBool());
+                    last_subnet->setDdnsGeneratedPrefix(out_bindings[64]->getString());
                 }
 
-                // reservations_out_of_pool at 65.
+                // ddns_qualifying_suffix at 65.
                 if (!out_bindings[65]->amNull()) {
-                    last_subnet->setReservationsOutOfPool(out_bindings[65]->getBool());
+                    last_subnet->setDdnsQualifyingSuffix(out_bindings[65]->getString());
                 }
 
-                // cache_threshold at 66.
+                // reservations_in_subnet at 66.
                 if (!out_bindings[66]->amNull()) {
-                    last_subnet->setCacheThreshold(out_bindings[66]->getFloat());
+                    last_subnet->setReservationsInSubnet(out_bindings[66]->getBool());
                 }
 
-                // cache_max_age at 67.
+                // reservations_out_of_pool at 67.
                 if (!out_bindings[67]->amNull()) {
-                    last_subnet->setCacheMaxAge(out_bindings[67]->getInteger<uint32_t>());
+                    last_subnet->setReservationsOutOfPool(out_bindings[67]->getBool());
+                }
+
+                // cache_threshold at 68.
+                if (!out_bindings[68]->amNull()) {
+                    last_subnet->setCacheThreshold(out_bindings[68]->getFloat());
                 }
 
-                // server_tag at 68.
+                // cache_max_age at 69.
+                if (!out_bindings[69]->amNull()) {
+                    last_subnet->setCacheMaxAge(out_bindings[69]->getInteger<uint32_t>());
+                }
+
+                // server_tag at 70.
 
                 // Subnet ready. Add it to the list.
                 auto ret = subnets.insert(last_subnet);
@@ -623,10 +625,10 @@ public:
                 }
             }
 
-            // Check for new server tags at 68.
-            if (!out_bindings[68]->amNull() &&
-                (last_tag != out_bindings[68]->getString())) {
-                last_tag = out_bindings[68]->getString();
+            // Check for new server tags at 70.
+            if (!out_bindings[70]->amNull() &&
+                (last_tag != out_bindings[70]->getString())) {
+                last_tag = out_bindings[70]->getString();
                 if (!last_tag.empty() && !last_subnet->hasServerTag(ServerTag(last_tag))) {
                     last_subnet->setServerTag(last_tag);
                 }
@@ -648,17 +650,17 @@ public:
                 last_pool = Pool4::create(IOAddress(out_bindings[21]->getInteger<uint32_t>()),
                                           IOAddress(out_bindings[22]->getInteger<uint32_t>()));
 
-                // pool client_class at 55.
-                if (!out_bindings[55]->amNull()) {
-                    last_pool->allowClientClass(out_bindings[55]->getString());
+                // pool client_class at 57.
+                if (!out_bindings[57]->amNull()) {
+                    last_pool->allowClientClass(out_bindings[57]->getString());
                 }
 
-                // pool require_client_classes at 56.
-                ElementPtr require_element = out_bindings[56]->getJSON();
+                // pool require_client_classes at 58.
+                ElementPtr require_element = out_bindings[58]->getJSON();
                 if (require_element) {
                     if (require_element->getType() != Element::list) {
                         isc_throw(BadValue, "invalid pool require_client_classes value "
-                                  << out_bindings[56]->getString());
+                                  << out_bindings[58]->getString());
                     }
                     for (auto i = 0; i < require_element->size(); ++i) {
                         auto require_item = require_element->get(i);
@@ -670,8 +672,8 @@ public:
                     }
                 }
 
-                // pool user_context at 57.
-                ElementPtr user_context = out_bindings[57]->getJSON();
+                // pool user_context at 59.
+                ElementPtr user_context = out_bindings[59]->getJSON();
                 if (user_context) {
                     last_pool->setContext(user_context);
                 }
@@ -679,7 +681,7 @@ public:
                 last_subnet->addPool(last_pool);
             }
 
-            // Parse pool-specific option from 25 to 36.
+            // Parse pool-specific option from 25 to 37.
             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>();
@@ -690,12 +692,12 @@ public:
                 }
             }
 
-            // Parse subnet-specific option from 37 to 48.
-            if (!out_bindings[37]->amNull() &&
-                (last_option_id < out_bindings[37]->getInteger<uint64_t>())) {
-                last_option_id = out_bindings[37]->getInteger<uint64_t>();
+            // 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>();
 
-                OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 37);
+                OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 38);
                 if (desc) {
                     last_subnet->getCfgOption()->add(*desc, desc->space_name_);
                 }
@@ -859,6 +861,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pool option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pool option: space
             MySqlBinding::createInteger<uint8_t>(), // pool option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // pool option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // pool option: dhcp4_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // pool option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool option: user_context
@@ -1322,6 +1325,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space
             MySqlBinding::createInteger<uint8_t>(), // option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // option: dhcp4_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context
@@ -1452,106 +1456,106 @@ public:
                 }
 
                 // valid_lifetime at 12.
-                // min_valid_lifetime at 32.
-                // max_valid_lifetime at 33.
+                // min_valid_lifetime at 33.
+                // max_valid_lifetime at 34.
                 if (!out_bindings[12]->amNull()) {
                     last_network->setValid(createTriplet(out_bindings[12],
-                                                         out_bindings[32],
-                                                         out_bindings[33]));
+                                                         out_bindings[33],
+                                                         out_bindings[34]));
                 }
 
-                // option from 13 to 24.
+                // option from 13 to 25.
 
-                // calculate_tee_times at 25.
-                if (!out_bindings[25]->amNull()) {
-                    last_network->setCalculateTeeTimes(out_bindings[25]->getBool());
-                }
-
-                // t1_percent at 26.
+                // calculate_tee_times at 26.
                 if (!out_bindings[26]->amNull()) {
-                    last_network->setT1Percent(out_bindings[26]->getFloat());
+                    last_network->setCalculateTeeTimes(out_bindings[26]->getBool());
                 }
 
-                // t2_percent at 27.
+                // t1_percent at 27.
                 if (!out_bindings[27]->amNull()) {
-                    last_network->setT2Percent(out_bindings[27]->getFloat());
+                    last_network->setT1Percent(out_bindings[27]->getFloat());
                 }
 
-                // authoritative at 28.
+                // t2_percent at 28.
                 if (!out_bindings[28]->amNull()) {
-                    last_network->setAuthoritative(out_bindings[28]->getBool());
+                    last_network->setT2Percent(out_bindings[28]->getFloat());
                 }
 
-                // boot_file_name at 29.
+                // authoritative at 29.
                 if (!out_bindings[29]->amNull()) {
-                    last_network->setFilename(out_bindings[29]->getString());
+                    last_network->setAuthoritative(out_bindings[29]->getBool());
                 }
 
-                // next_server at 30.
+                // boot_file_name at 30.
                 if (!out_bindings[30]->amNull()) {
-                    last_network->setSiaddr(IOAddress(out_bindings[30]->getInteger<uint32_t>()));
+                    last_network->setFilename(out_bindings[30]->getString());
                 }
 
-                // server_hostname at 31.
+                // next_server at 31.
                 if (!out_bindings[31]->amNull()) {
-                    last_network->setSname(out_bindings[31]->getString());
+                    last_network->setSiaddr(IOAddress(out_bindings[31]->getInteger<uint32_t>()));
                 }
 
-                // min_valid_lifetime at 32.
-                // max_valid_lifetime at 33.
-
-                // ddns_send_updates at 34.
-                if (!out_bindings[34]->amNull()) {
-                    last_network->setDdnsSendUpdates(out_bindings[34]->getBool());
+                // server_hostname at 32.
+                if (!out_bindings[32]->amNull()) {
+                    last_network->setSname(out_bindings[32]->getString());
                 }
 
-                // ddns_override_no_update at 35.
+                // min_valid_lifetime at 33.
+                // max_valid_lifetime at 34.
+
+                // ddns_send_updates at 35.
                 if (!out_bindings[35]->amNull()) {
-                    last_network->setDdnsOverrideNoUpdate(out_bindings[35]->getBool());
+                    last_network->setDdnsSendUpdates(out_bindings[35]->getBool());
                 }
 
-                // ddns_override_client_update at 36.
+                // ddns_override_no_update at 36.
                 if (!out_bindings[36]->amNull()) {
-                    last_network->setDdnsOverrideClientUpdate(out_bindings[36]->getBool());
+                    last_network->setDdnsOverrideNoUpdate(out_bindings[36]->getBool());
                 }
 
-                // ddns_replace_client_name at 37.
+                // ddns_override_client_update at 37.
                 if (!out_bindings[37]->amNull()) {
-                    last_network->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode>
-                        (out_bindings[37]->getInteger<uint8_t>()));
+                    last_network->setDdnsOverrideClientUpdate(out_bindings[37]->getBool());
                 }
 
-                // ddns_generated_prefix at 38.
+                // ddns_replace_client_name at 38.
                 if (!out_bindings[38]->amNull()) {
-                    last_network->setDdnsGeneratedPrefix(out_bindings[38]->getString());
+                    last_network->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode>
+                        (out_bindings[38]->getInteger<uint8_t>()));
                 }
 
-                // ddns_qualifying_suffix at 39.
+                // ddns_generated_prefix at 39.
                 if (!out_bindings[39]->amNull()) {
-                    last_network->setDdnsQualifyingSuffix(out_bindings[39]->getString());
+                    last_network->setDdnsGeneratedPrefix(out_bindings[39]->getString());
                 }
 
-                // reservations_in_subnet at 40.
+                // ddns_qualifying_suffix at 40.
                 if (!out_bindings[40]->amNull()) {
-                    last_network->setReservationsInSubnet(out_bindings[40]->getBool());
+                    last_network->setDdnsQualifyingSuffix(out_bindings[40]->getString());
                 }
 
                 // reservations_in_subnet at 41.
                 if (!out_bindings[41]->amNull()) {
-                    last_network->setReservationsOutOfPool(out_bindings[41]->getBool());
+                    last_network->setReservationsInSubnet(out_bindings[41]->getBool());
                 }
 
-                // cache_threshold at 42.
+                // reservations_in_subnet at 42.
                 if (!out_bindings[42]->amNull()) {
-                    last_network->setCacheThreshold(out_bindings[42]->getFloat());
+                    last_network->setReservationsOutOfPool(out_bindings[42]->getBool());
                 }
 
-                // cache_max_age at 43.
+                // cache_threshold at 43.
                 if (!out_bindings[43]->amNull()) {
-                    last_network->setCacheMaxAge(out_bindings[43]->getInteger<uint32_t>());
+                    last_network->setCacheThreshold(out_bindings[43]->getFloat());
                 }
 
-                // server_tag at 44.
+                // cache_max_age at 44.
+                if (!out_bindings[44]->amNull()) {
+                    last_network->setCacheMaxAge(out_bindings[44]->getInteger<uint32_t>());
+                }
+
+                // server_tag at 45.
 
                 // Add the shared network.
                 auto ret = shared_networks.push_back(last_network);
@@ -1565,15 +1569,15 @@ public:
             }
 
             // Check for new server tags.
-            if (!out_bindings[44]->amNull() &&
-                (last_tag != out_bindings[44]->getString())) {
-                last_tag = out_bindings[44]->getString();
+            if (!out_bindings[45]->amNull() &&
+                (last_tag != out_bindings[45]->getString())) {
+                last_tag = out_bindings[45]->getString();
                 if (!last_tag.empty() && !last_network->hasServerTag(ServerTag(last_tag))) {
                     last_network->setServerTag(last_tag);
                 }
             }
 
-            // Parse option from 13 to 24.
+            // Parse option from 13 to 25.
             if (!out_bindings[13]->amNull() &&
                 (last_option_id < out_bindings[13]->getInteger<uint64_t>())) {
                 last_option_id = out_bindings[13]->getInteger<uint64_t>();
@@ -1793,7 +1797,7 @@ public:
         auto option_id = mysql_insert_id(conn_.mysql_);
 
         // Timestamp is expected to be in this input binding.
-        auto timestamp_binding = in_bindings[11];
+        auto timestamp_binding = in_bindings[12];
 
         // Associate the option with the servers.
         attachElementToServers(MySqlConfigBackendDHCPv4Impl::INSERT_OPTION4_SERVER,
@@ -1821,6 +1825,7 @@ public:
             MySqlBinding::condCreateString(option->formatted_value_),
             MySqlBinding::condCreateString(option->space_name_),
             MySqlBinding::createBool(option->persistent_),
+            MySqlBinding::createBool(option->cancelled_),
             MySqlBinding::createNull(),
             MySqlBinding::createNull(),
             MySqlBinding::createInteger<uint8_t>(0),
@@ -1874,6 +1879,7 @@ public:
             MySqlBinding::condCreateString(option->formatted_value_),
             MySqlBinding::condCreateString(option->space_name_),
             MySqlBinding::createBool(option->persistent_),
+            MySqlBinding::createBool(option->cancelled_),
             MySqlBinding::createNull(),
             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)),
             MySqlBinding::createInteger<uint8_t>(1),
@@ -1958,6 +1964,7 @@ public:
             MySqlBinding::condCreateString(option->formatted_value_),
             MySqlBinding::condCreateString(option->space_name_),
             MySqlBinding::createBool(option->persistent_),
+            MySqlBinding::createBool(option->cancelled_),
             MySqlBinding::createNull(),
             MySqlBinding::createNull(),
             MySqlBinding::createInteger<uint8_t>(5),
@@ -2013,6 +2020,7 @@ public:
             MySqlBinding::condCreateString(option->formatted_value_),
             MySqlBinding::condCreateString(option->space_name_),
             MySqlBinding::createBool(option->persistent_),
+            MySqlBinding::createBool(option->cancelled_),
             MySqlBinding::createNull(),
             MySqlBinding::createNull(),
             MySqlBinding::createInteger<uint8_t>(4),
@@ -2073,6 +2081,7 @@ public:
             MySqlBinding::condCreateString(option->formatted_value_),
             MySqlBinding::condCreateString(option->space_name_),
             MySqlBinding::createBool(option->persistent_),
+            MySqlBinding::createBool(option->cancelled_),
             MySqlBinding::createString(client_class->getName()),
             MySqlBinding::createNull(),
             MySqlBinding::createInteger<uint8_t>(2),
@@ -2385,6 +2394,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space
             MySqlBinding::createInteger<uint8_t>(), // option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // option: dhcp4_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context
@@ -2470,9 +2480,9 @@ public:
             }
 
             // server tag
-            if (!out_bindings[36]->amNull() &&
-                (last_tag != out_bindings[36]->getString())) {
-                last_tag = out_bindings[36]->getString();
+            if (!out_bindings[37]->amNull() &&
+                (last_tag != out_bindings[37]->getString())) {
+                last_tag = out_bindings[37]->getString();
                 if (!last_tag.empty() && !last_client_class->hasServerTag(ServerTag(last_tag))) {
                     last_client_class->setServerTag(last_tag);
                 }
@@ -2489,7 +2499,7 @@ public:
                 }
             }
 
-            // Parse client class specific option from 24 to 35.
+            // Parse client class specific option from 24 to 36.
             if (!out_bindings[24]->amNull() &&
                 (last_option_id < out_bindings[24]->getInteger<uint64_t>())) {
                 last_option_id = out_bindings[24]->getInteger<uint64_t>();
index 83b37141a2b67a3968415c2d615e28e9cd616ef8..05c7da53280e9d18116da5d423834cd3c97c70a5 100644 (file)
@@ -326,6 +326,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pool option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pool option: space
             MySqlBinding::createInteger<uint8_t>(), // pool option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // pool option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // pool option: dhcp6_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // pool option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool option: user_context
@@ -339,6 +340,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pd pool option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pd pool option: space
             MySqlBinding::createInteger<uint8_t>(), // pd pool option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // pd pool option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // pd pool option: dhcp6_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // pd pool option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool option: user_context
@@ -352,6 +354,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space
             MySqlBinding::createInteger<uint8_t>(), // option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // option: dhcp6_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context
@@ -436,11 +439,11 @@ public:
                 auto prefix_pair = Subnet6::parsePrefix(subnet_prefix);
 
                 // preferred_lifetime (5)
-                // min_preferred_lifetime (69)
-                // max_preferred_lifetime (70)
+                // min_preferred_lifetime (72)
+                // max_preferred_lifetime (73)
                 auto preferred_lifetime = createTriplet(out_bindings[5],
-                                                        out_bindings[69],
-                                                        out_bindings[70]);
+                                                        out_bindings[72],
+                                                        out_bindings[73]);
 
                 // renew_timer (9)
                 auto renew_timer = createTriplet(out_bindings[9]);
@@ -449,11 +452,11 @@ public:
                 auto rebind_timer = createTriplet(out_bindings[7]);
 
                 // valid_lifetime (14)
-                // min_valid_lifetime (71)
-                // max_valid_lifetime (72)
+                // min_valid_lifetime (74)
+                // max_valid_lifetime (75)
                 auto valid_lifetime = createTriplet(out_bindings[14],
-                                                    out_bindings[71],
-                                                    out_bindings[72]);
+                                                    out_bindings[74],
+                                                    out_bindings[75]);
 
                 // Create subnet with basic settings.
                 last_subnet = Subnet6::create(prefix_pair.first, prefix_pair.second,
@@ -539,28 +542,28 @@ public:
 
                 // 15 to 19 are pool
                 // 20 to 25 are pd pool
-                // 26 to 38 are pool option
-                // 39 to 51 are pd pool option
-                // 52 to 64 are option
+                // 26 to 39 are pool option
+                // 40 to 53 are pd pool option
+                // 54 to 67 are option
 
-                // calculate_tee_times (65)
-                if (!out_bindings[65]->amNull()) {
-                    last_subnet->setCalculateTeeTimes(out_bindings[65]->getBool());
+                // calculate_tee_times (68)
+                if (!out_bindings[68]->amNull()) {
+                    last_subnet->setCalculateTeeTimes(out_bindings[68]->getBool());
                 }
 
-                // t1_percent (66)
-                if (!out_bindings[66]->amNull()) {
-                    last_subnet->setT1Percent(out_bindings[66]->getFloat());
+                // t1_percent (69)
+                if (!out_bindings[69]->amNull()) {
+                    last_subnet->setT1Percent(out_bindings[69]->getFloat());
                 }
 
-                // t2_percent (67)
-                if (!out_bindings[67]->amNull()) {
-                    last_subnet->setT2Percent(out_bindings[67]->getFloat());
+                // t2_percent (70)
+                if (!out_bindings[70]->amNull()) {
+                    last_subnet->setT2Percent(out_bindings[70]->getFloat());
                 }
 
-                // interface_id (68)
-                if (!out_bindings[68]->amNull()) {
-                    auto iface_id_data = out_bindings[68]->getBlob();
+                // interface_id (71)
+                if (!out_bindings[71]->amNull()) {
+                    auto iface_id_data = out_bindings[71]->getBlob();
                     if (!iface_id_data.empty()) {
                         OptionPtr opt_iface_id(new Option(Option::V6, D6O_INTERFACE_ID,
                                                           iface_id_data));
@@ -568,71 +571,71 @@ public:
                     }
                 }
 
-                // 69 and 70 are {min,max}_preferred_lifetime
-
-                // 71 and 72 are {min,max}_valid_lifetime
-
-                // 73 is pool client_class
-                // 74 is pool require_client_classes
-                // 75 is pool user_context
-                // 76 is pd pool excluded_prefix
-                // 77 is pd pool excluded_prefix_length
-                // 78 is pd pool client_class
-                // 79 is pd pool require_client_classes
-                // 80 is pd pool user_context
+                // 72 and 73 are {min,max}_preferred_lifetime
 
-                // ddns_send_updates (81)
-                if (!out_bindings[81]->amNull()) {
-                    last_subnet->setDdnsSendUpdates(out_bindings[81]->getBool());
-                }
+                // 74 and 75 are {min,max}_valid_lifetime
 
-                // ddns_override_no_update (82)
-                if (!out_bindings[82]->amNull()) {
-                    last_subnet->setDdnsOverrideNoUpdate(out_bindings[82]->getBool());
-                }
+                // 76 is pool client_class
+                // 77 is pool require_client_classes
+                // 78 is pool user_context
+                // 79 is pd pool excluded_prefix
+                // 80 is pd pool excluded_prefix_length
+                // 81 is pd pool client_class
+                // 82 is pd pool require_client_classes
+                // 83 is pd pool user_context
 
-                // ddns_override_client_update (83)
-                if (!out_bindings[83]->amNull()) {
-                    last_subnet->setDdnsOverrideClientUpdate(out_bindings[83]->getBool());
-                }
-
-                // ddns_replace_client_name (84)
+                // ddns_send_updates (84)
                 if (!out_bindings[84]->amNull()) {
-                    last_subnet->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode>
-                        (out_bindings[84]->getInteger<uint8_t>()));
+                    last_subnet->setDdnsSendUpdates(out_bindings[84]->getBool());
                 }
 
-                // ddns_generated_prefix (85)
+                // ddns_override_no_update (85)
                 if (!out_bindings[85]->amNull()) {
-                    last_subnet->setDdnsGeneratedPrefix(out_bindings[85]->getString());
+                    last_subnet->setDdnsOverrideNoUpdate(out_bindings[85]->getBool());
                 }
 
-                // ddns_qualifying_suffix (86)
+                // ddns_override_client_update (86)
                 if (!out_bindings[86]->amNull()) {
-                    last_subnet->setDdnsQualifyingSuffix(out_bindings[86]->getString());
+                    last_subnet->setDdnsOverrideClientUpdate(out_bindings[86]->getBool());
                 }
 
-                // reservations_in_subnet (87)
+                // ddns_replace_client_name (87)
                 if (!out_bindings[87]->amNull()) {
-                    last_subnet->setReservationsInSubnet(out_bindings[87]->getBool());
+                    last_subnet->setDdnsReplaceClientNameMode(static_cast<D2ClientConfig::ReplaceClientNameMode>
+                        (out_bindings[87]->getInteger<uint8_t>()));
                 }
 
-                // reservations_out_of_pool (88)
+                // ddns_generated_prefix (88)
                 if (!out_bindings[88]->amNull()) {
-                    last_subnet->setReservationsOutOfPool(out_bindings[88]->getBool());
+                    last_subnet->setDdnsGeneratedPrefix(out_bindings[88]->getString());
                 }
 
-                // cache_threshold (89)
+                // ddns_qualifying_suffix (89)
                 if (!out_bindings[89]->amNull()) {
-                    last_subnet->setCacheThreshold(out_bindings[89]->getFloat());
+                    last_subnet->setDdnsQualifyingSuffix(out_bindings[89]->getString());
                 }
 
-                // cache_max_age (90)
+                // reservations_in_subnet (90)
                 if (!out_bindings[90]->amNull()) {
-                    last_subnet->setCacheMaxAge(out_bindings[90]->getInteger<uint32_t>());
+                    last_subnet->setReservationsInSubnet(out_bindings[90]->getBool());
+                }
+
+                // reservations_out_of_pool (91)
+                if (!out_bindings[91]->amNull()) {
+                    last_subnet->setReservationsOutOfPool(out_bindings[91]->getBool());
+                }
+
+                // cache_threshold (92)
+                if (!out_bindings[92]->amNull()) {
+                    last_subnet->setCacheThreshold(out_bindings[92]->getFloat());
                 }
 
-                // server_tag (91 / last)
+                // cache_max_age (93)
+                if (!out_bindings[93]->amNull()) {
+                    last_subnet->setCacheMaxAge(out_bindings[93]->getInteger<uint32_t>());
+                }
+
+                // server_tag (94 / last)
 
                 // Subnet ready. Add it to the list.
                 auto ret = subnets.insert(last_subnet);
@@ -646,15 +649,15 @@ public:
             }
 
             // Check for new server tags.
-            if (!out_bindings[91]->amNull() &&
-                (last_tag != out_bindings[91]->getString())) {
-                last_tag = out_bindings[91]->getString();
+            if (!out_bindings[94]->amNull() &&
+                (last_tag != out_bindings[94]->getString())) {
+                last_tag = out_bindings[94]->getString();
                 if (!last_tag.empty() && !last_subnet->hasServerTag(ServerTag(last_tag))) {
                     last_subnet->setServerTag(last_tag);
                 }
             }
 
-            // Pool is between 15 and 19 with extra between 73 and 75
+            // Pool is between 15 and 19 with extra between 76 and 78
 
             // If the row contains information about the pool and it
             // appears to be new pool entry (checked by comparing pool
@@ -675,17 +678,17 @@ public:
                 // 18 is pool subnet_id (ignored)
                 // 19 is pool modification_ts (ignored)
 
-                // pool client_class (73)
-                if (!out_bindings[73]->amNull()) {
-                    last_pool->allowClientClass(out_bindings[73]->getString());
+                // pool client_class (76)
+                if (!out_bindings[76]->amNull()) {
+                    last_pool->allowClientClass(out_bindings[76]->getString());
                 }
 
-                // pool require_client_classes (74)
-                ElementPtr require_element = out_bindings[74]->getJSON();
+                // pool require_client_classes (77)
+                ElementPtr require_element = out_bindings[77]->getJSON();
                 if (require_element) {
                     if (require_element->getType() != Element::list) {
                         isc_throw(BadValue, "invalid pool require_client_classes value "
-                                  << out_bindings[74]->getString());
+                                  << out_bindings[77]->getString());
                     }
                     for (auto i = 0; i < require_element->size(); ++i) {
                         auto require_item = require_element->get(i);
@@ -697,8 +700,8 @@ public:
                     }
                 }
 
-                // pool user_context (75)
-                ElementPtr user_context = out_bindings[75]->getJSON();
+                // pool user_context (78)
+                ElementPtr user_context = out_bindings[78]->getJSON();
                 if (user_context) {
                     last_pool->setContext(user_context);
                 }
@@ -706,7 +709,7 @@ public:
                 last_subnet->addPool(last_pool);
             }
 
-            // Pd Pool is between 20 and 25 with extra between 76 and 80
+            // Pd Pool is between 20 and 25 with extra between 79 and 83
 
             // If the row contains information about the pd pool and
             // it appears to be new pd pool entry (checked by
@@ -726,28 +729,28 @@ public:
                 // 24 is pd pool subnet_id (ignored)
                 // 25 is pd pool modification_ts (ignored)
 
-                // excluded_prefix (76) and excluded_prefix_length (77)
+                // excluded_prefix (79) and excluded_prefix_length (80)
                 IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS();
-                if (!out_bindings[76]->amNull()) {
-                    excluded_prefix = IOAddress(out_bindings[76]->getString());
+                if (!out_bindings[79]->amNull()) {
+                    excluded_prefix = IOAddress(out_bindings[79]->getString());
                 }
                 last_pd_pool = Pool6::create(IOAddress(out_bindings[21]->getString()),
                                              out_bindings[22]->getInteger<uint8_t>(),
                                              out_bindings[23]->getInteger<uint8_t>(),
                                              excluded_prefix,
-                                             out_bindings[77]->getInteger<uint8_t>());
+                                             out_bindings[80]->getInteger<uint8_t>());
 
-                // pd pool client_class (78)
-                if (!out_bindings[78]->amNull()) {
-                    last_pd_pool->allowClientClass(out_bindings[78]->getString());
+                // pd pool client_class (81)
+                if (!out_bindings[81]->amNull()) {
+                    last_pd_pool->allowClientClass(out_bindings[81]->getString());
                 }
 
-                // pd pool require_client_classes (79)
-                ElementPtr require_element = out_bindings[79]->getJSON();
+                // pd pool require_client_classes (82)
+                ElementPtr require_element = out_bindings[82]->getJSON();
                 if (require_element) {
                     if (require_element->getType() != Element::list) {
                         isc_throw(BadValue, "invalid pd pool require_client_classes value "
-                                  << out_bindings[79]->getString());
+                                  << out_bindings[82]->getString());
                     }
                     for (auto i = 0; i < require_element->size(); ++i) {
                         auto require_item = require_element->get(i);
@@ -759,8 +762,8 @@ public:
                     }
                 }
 
-                // pd pool user_context (80)
-                ElementPtr user_context = out_bindings[80]->getJSON();
+                // pd pool user_context (83)
+                ElementPtr user_context = out_bindings[83]->getJSON();
                 if (user_context) {
                     last_pd_pool->setContext(user_context);
                 }
@@ -768,7 +771,7 @@ public:
                 last_subnet->addPool(last_pd_pool);
             }
 
-            // Parse pool specific option between 26 and 38
+            // Parse pool specific option between 26 and 39
             if (last_pool && !out_bindings[26]->amNull() &&
                 (last_pool_option_id < out_bindings[26]->getInteger<uint64_t>())) {
                 last_pool_option_id = out_bindings[26]->getInteger<uint64_t>();
@@ -779,23 +782,23 @@ public:
                 }
             }
 
-            // Parse pd pool specific option between 39 and 51
-            if (last_pd_pool && !out_bindings[39]->amNull() &&
-                (last_pd_pool_option_id < out_bindings[39]->getInteger<uint64_t>())) {
-                last_pd_pool_option_id = out_bindings[39]->getInteger<uint64_t>();
+            // Parse pd pool specific option between 40 and 53
+            if (last_pd_pool && !out_bindings[40]->amNull() &&
+                (last_pd_pool_option_id < out_bindings[40]->getInteger<uint64_t>())) {
+                last_pd_pool_option_id = out_bindings[40]->getInteger<uint64_t>();
 
-                OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 39);
+                OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 40);
                 if (desc) {
                     last_pd_pool->getCfgOption()->add(*desc, desc->space_name_);
                 }
             }
 
-            // Parse subnet specific option between 52 and 64
-            if (!out_bindings[52]->amNull() &&
-                (last_option_id < out_bindings[52]->getInteger<uint64_t>())) {
-                last_option_id = out_bindings[52]->getInteger<uint64_t>();
+            // Parse subnet specific option between 54 and 67
+            if (!out_bindings[54]->amNull() &&
+                (last_option_id < out_bindings[54]->getInteger<uint64_t>())) {
+                last_option_id = out_bindings[54]->getInteger<uint64_t>();
 
-                OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 52);
+                OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 54);
                 if (desc) {
                     last_subnet->getCfgOption()->add(*desc, desc->space_name_);
                 }
@@ -959,6 +962,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pool option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pool option: space
             MySqlBinding::createInteger<uint8_t>(), // pool option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // pool option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // pool option: dhcp6_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // pool option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool option: user_context
@@ -1070,6 +1074,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pd pool option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pd pool option: space
             MySqlBinding::createInteger<uint8_t>(), // pd pool option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // pd pool option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // pd pool option: dhcp6_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // pd pool option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool option: user_context
@@ -1143,7 +1148,7 @@ public:
                 pd_pool_ids.push_back(last_pd_pool_id);
             }
 
-            // Parse pd pool specific option between 11 and 24
+            // Parse pd pool specific option between 11 and 25
             if (last_pd_pool && !out_bindings[11]->amNull() &&
                 (last_pd_pool_option_id < out_bindings[11]->getInteger<uint64_t>())) {
                 last_pd_pool_option_id = out_bindings[11]->getInteger<uint64_t>();
@@ -1649,6 +1654,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space
             MySqlBinding::createInteger<uint8_t>(), // option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // option: dhcp6_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context
@@ -1720,12 +1726,12 @@ public:
                 last_network->setModificationTime(out_bindings[4]->getTimestamp());
 
                 // preferred_lifetime at 5.
-                // min_preferred_lifetime at 31.
-                // max_preferred_lifetime at 32.
+                // min_preferred_lifetime at 32.
+                // max_preferred_lifetime at 33.
                 if (!out_bindings[5]->amNull()) {
                     last_network->setPreferred(createTriplet(out_bindings[5],
-                                                             out_bindings[31],
-                                                             out_bindings[32]));
+                                                             out_bindings[32],
+                                                             out_bindings[33]));
                 }
 
                 // rapid_commit at 6.
@@ -1788,34 +1794,34 @@ public:
                 }
 
                 // valid_lifetime at 13.
-                // min_valid_lifetime at 33.
-                // max_valid_lifetime at 34.
+                // min_valid_lifetime at 34.
+                // max_valid_lifetime at 35.
                 if (!out_bindings[13]->amNull()) {
                     last_network->setValid(createTriplet(out_bindings[13],
-                                                         out_bindings[33],
-                                                         out_bindings[34]));
+                                                         out_bindings[34],
+                                                         out_bindings[35]));
                 }
 
-                // 14 to 26 are option.
-
-                // calculate_tee_times at 27.
-                if (!out_bindings[27]->amNull()) {
-                    last_network->setCalculateTeeTimes(out_bindings[27]->getBool());
-                }
+                // 14 to 27 are option.
 
-                // t1_percent at 28.
+                // calculate_tee_times at 28.
                 if (!out_bindings[28]->amNull()) {
-                    last_network->setT1Percent(out_bindings[28]->getFloat());
+                    last_network->setCalculateTeeTimes(out_bindings[28]->getBool());
                 }
 
-                // t2_percent at 29.
+                // t1_percent at 29.
                 if (!out_bindings[29]->amNull()) {
-                    last_network->setT2Percent(out_bindings[29]->getFloat());
+                    last_network->setT1Percent(out_bindings[29]->getFloat());
                 }
 
-                // interface_id at 30.
+                // t2_percent at 30.
                 if (!out_bindings[30]->amNull()) {
-                    auto iface_id_data = out_bindings[30]->getBlob();
+                    last_network->setT2Percent(out_bindings[30]->getFloat());
+                }
+
+                // interface_id at 31.
+                if (!out_bindings[31]->amNull()) {
+                    auto iface_id_data = out_bindings[31]->getBlob();
                     if (!iface_id_data.empty()) {
                         OptionPtr opt_iface_id(new Option(Option::V6, D6O_INTERFACE_ID,
                                                           iface_id_data));
@@ -1823,63 +1829,63 @@ public:
                     }
                 }
 
-                // min_preferred_lifetime at 31.
-                // max_preferred_lifetime at 32.
-                // 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());
-                }
+                // min_preferred_lifetime at 32.
+                // max_preferred_lifetime at 33.
+                // min_valid_lifetime at 34.
+                // max_valid_lifetime at 35.
 
-                // ddns_override_no_update at 36.
+                // 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());
+                }
+
+                // cache_max_age at 45.
+                if (!out_bindings[45]->amNull()) {
+                    last_network->setCacheMaxAge(out_bindings[45]->getInteger<uint32_t>());
                 }
 
-                // server_tag at 45.
+                // server_tag at 46.
 
                 // Add the shared network.
                 auto ret = shared_networks.push_back(last_network);
@@ -1893,15 +1899,15 @@ public:
             }
 
             // Check for new server tags.
-            if (!out_bindings[45]->amNull() &&
-                (last_tag != out_bindings[45]->getString())) {
-                last_tag = out_bindings[45]->getString();
+            if (!out_bindings[46]->amNull() &&
+                (last_tag != out_bindings[46]->getString())) {
+                last_tag = out_bindings[46]->getString();
                 if (!last_tag.empty() && !last_network->hasServerTag(ServerTag(last_tag))) {
                     last_network->setServerTag(last_tag);
                 }
             }
 
-            // Parse option from 14 to 26.
+            // Parse option from 14 to 27.
             if (!out_bindings[14]->amNull() &&
                 (last_option_id < out_bindings[14]->getInteger<uint64_t>())) {
                 last_option_id = out_bindings[14]->getInteger<uint64_t>();
@@ -2132,7 +2138,7 @@ public:
         auto option_id = mysql_insert_id(conn_.mysql_);
 
         // Timestamp is expected to be in this input binding.
-        auto timestamp_binding = in_bindings[11];
+        auto timestamp_binding = in_bindings[12];
 
         // Associate the option with the servers.
         attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_OPTION6_SERVER,
@@ -2160,6 +2166,7 @@ public:
             MySqlBinding::condCreateString(option->formatted_value_),
             MySqlBinding::condCreateString(option->space_name_),
             MySqlBinding::createBool(option->persistent_),
+            MySqlBinding::createBool(option->cancelled_),
             MySqlBinding::createNull(),
             MySqlBinding::createNull(),
             MySqlBinding::createInteger<uint8_t>(0),
@@ -2214,6 +2221,7 @@ public:
             MySqlBinding::condCreateString(option->formatted_value_),
             MySqlBinding::condCreateString(option->space_name_),
             MySqlBinding::createBool(option->persistent_),
+            MySqlBinding::createBool(option->cancelled_),
             MySqlBinding::createNull(),
             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)),
             MySqlBinding::createInteger<uint8_t>(1),
@@ -2342,6 +2350,8 @@ public:
         in_bindings.push_back(MySqlBinding::condCreateString(option->space_name_));
         // persistent
         in_bindings.push_back(MySqlBinding::createBool(option->persistent_));
+        // cancelled
+        in_bindings.push_back(MySqlBinding::createBool(option->cancelled_));
         // dhcp_client_class
         in_bindings.push_back(MySqlBinding::createNull());
         // dhcp[46]_subnet_id
@@ -2426,6 +2436,7 @@ public:
             MySqlBinding::condCreateString(option->formatted_value_),
             MySqlBinding::condCreateString(option->space_name_),
             MySqlBinding::createBool(option->persistent_),
+            MySqlBinding::createBool(option->cancelled_),
             MySqlBinding::createNull(),
             MySqlBinding::createNull(),
             MySqlBinding::createInteger<uint8_t>(4),
@@ -2487,6 +2498,7 @@ public:
             MySqlBinding::condCreateString(option->formatted_value_),
             MySqlBinding::condCreateString(option->space_name_),
             MySqlBinding::createBool(option->persistent_),
+            MySqlBinding::createBool(option->cancelled_),
             MySqlBinding::createString(client_class->getName()),
             MySqlBinding::createNull(),
             MySqlBinding::createInteger<uint8_t>(2),
@@ -2825,6 +2837,7 @@ public:
             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value
             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space
             MySqlBinding::createInteger<uint8_t>(), // option: persistent
+            MySqlBinding::createInteger<uint8_t>(), // option: cancelled
             MySqlBinding::createInteger<uint32_t>(), // option: dhcp6_subnet_id
             MySqlBinding::createInteger<uint8_t>(), // option: scope_id
             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context
@@ -2895,17 +2908,17 @@ public:
                 }
 
                 // preferred lifetime: default, min, max
-                last_client_class->setPreferred(createTriplet(out_bindings[34],
-                                                              out_bindings[35],
-                                                              out_bindings[36]));
+                last_client_class->setPreferred(createTriplet(out_bindings[35],
+                                                              out_bindings[36],
+                                                              out_bindings[37]));
 
                 class_list.push_back(last_client_class);
             }
 
             // server tag
-            if (!out_bindings[33]->amNull() &&
-                (last_tag != out_bindings[33]->getString())) {
-                last_tag = out_bindings[33]->getString();
+            if (!out_bindings[34]->amNull() &&
+                (last_tag != out_bindings[34]->getString())) {
+                last_tag = out_bindings[34]->getString();
                 if (!last_tag.empty() && !last_client_class->hasServerTag(ServerTag(last_tag))) {
                     last_client_class->setServerTag(last_tag);
                 }
@@ -2922,7 +2935,7 @@ public:
                 }
             }
 
-            // Parse client class specific option from 21 to 32.
+            // Parse client class specific option from 21 to 33.
             if (!out_bindings[21]->amNull() &&
                 (last_option_id < out_bindings[21]->getInteger<uint64_t>())) {
                 last_option_id = out_bindings[21]->getInteger<uint64_t>();
index f4a05637f3bd326b3ba9c603f7b1dbaa61ac547b..dafe462190a6aa2d94f50c99427a385e3bb0a81e 100644 (file)
@@ -740,12 +740,14 @@ MySqlConfigBackendImpl::getOptions(const int index,
     }
     // value
     out_bindings.push_back(MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH));
-    // forma\tted_value
+    // formatted_value
     out_bindings.push_back(MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH));
     // space
     out_bindings.push_back(MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH));
     // persistent
     out_bindings.push_back(MySqlBinding::createInteger<uint8_t>());
+    // cancelled
+    out_bindings.push_back(MySqlBinding::createInteger<uint8_t>());
     // dhcp[46]_subnet_id
     out_bindings.push_back(MySqlBinding::createInteger<uint32_t>());
     // scope_id
@@ -781,7 +783,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[12]->getString());
+                ServerTag last_option_server_tag(out_bindings[13]->getString());
                 desc->setServerTag(last_option_server_tag.get());
 
                 // If we're fetching options for a given server (explicit server
@@ -858,12 +860,18 @@ MySqlConfigBackendImpl::processOptionRow(const Option::Universe& universe,
     // Check if the option is persistent.
     bool persistent = static_cast<bool>((*(first_binding + 5))->getIntegerOrDefault<uint8_t>(0));
 
+    // Check if the option is cancelled.
+    bool cancelled = static_cast<bool>((*(first_binding + 6))->getIntegerOrDefault<uint8_t>(0));
+
     // Create option descriptor which encapsulates our option and adds
     // additional information, i.e. whether the option is persistent,
     // its option space and timestamp.
-    OptionDescriptorPtr desc = OptionDescriptor::create(option, persistent, formatted_value);
+    OptionDescriptorPtr desc = OptionDescriptor::create(option,
+                                                        persistent,
+                                                        cancelled,
+                                                        formatted_value);
     desc->space_name_ = space;
-    desc->setModificationTime((*(first_binding + 11))->getTimestamp());
+    desc->setModificationTime((*(first_binding + 12))->getTimestamp());
 
     // Set database id for the option.
     if (!(*first_binding)->amNull()) {
index 2422a601c7b36efa954f94b9e7832332a4983788..24d4152b7eb5f60291d79bfa7e35763cc1fc8ed4 100644 (file)
@@ -562,6 +562,7 @@ public:
     /// - formatted_value,
     /// - space,
     /// - persistent,
+    /// - cancelled,
     /// - dhcp4_subnet_id/dhcp6_subnet_id,
     /// - scope_id,
     /// - user_context,
index f0525d44b3ffbbf4260c12fb4551b04b22f97cb9..2f8906239c1322b519a5f1da09ee98553fe9b5c6 100644 (file)
@@ -81,6 +81,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp4_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -93,6 +94,7 @@ namespace {
     "  o.formatted_value," \
     "  o.space," \
     "  o.persistent," \
+    "  o.cancelled," \
     "  o.dhcp4_subnet_id," \
     "  o.scope_id," \
     "  o.user_context," \
@@ -187,6 +189,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp6_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -200,6 +203,7 @@ namespace {
     "  y.formatted_value," \
     "  y.space," \
     "  y.persistent," \
+    "  y.cancelled," \
     "  y.dhcp6_subnet_id," \
     "  y.scope_id," \
     "  y.user_context," \
@@ -213,6 +217,7 @@ namespace {
     "  o.formatted_value," \
     "  o.space," \
     "  o.persistent," \
+    "  o.cancelled," \
     "  o.dhcp6_subnet_id," \
     "  o.scope_id," \
     "  o.user_context," \
@@ -299,6 +304,7 @@ namespace {
       "  x.formatted_value," \
       "  x.space," \
       "  x.persistent," \
+      "  x.cancelled," \
       "  x.dhcp4_subnet_id," \
       "  x.scope_id," \
       "  x.user_context," \
@@ -339,6 +345,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp6_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -383,6 +390,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp6_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -429,6 +437,7 @@ namespace {
     "  o.formatted_value," \
     "  o.space," \
     "  o.persistent," \
+    "  o.cancelled," \
     "  o.dhcp4_subnet_id," \
     "  o.scope_id," \
     "  o.user_context," \
@@ -509,6 +518,7 @@ namespace {
     "  o.formatted_value," \
     "  o.space," \
     "  o.persistent," \
+    "  o.cancelled," \
     "  o.dhcp6_subnet_id," \
     "  o.scope_id," \
     "  o.user_context," \
@@ -598,6 +608,7 @@ namespace {
     "  o.formatted_value," \
     "  o.space," \
     "  o.persistent," \
+    "  o.cancelled," \
     "  o." #table_prefix "_subnet_id," \
     "  o.scope_id," \
     "  o.user_context," \
@@ -692,6 +703,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp4_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -755,6 +767,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp6_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -909,6 +922,7 @@ namespace {
     "  formatted_value," \
     "  space," \
     "  persistent," \
+    "  cancelled," \
     "  dhcp_client_class," \
     " " #table_prefix "_subnet_id," \
     "  scope_id," \
@@ -917,7 +931,7 @@ namespace {
     "  pool_id," \
     "  modification_ts" \
     pd_pool_id \
-    ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?" last ")"
+    ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?" last ")"
 
 #define MYSQL_INSERT_OPTION4() \
     MYSQL_INSERT_OPTION_COMMON(dhcp4, "", "")
@@ -1028,6 +1042,7 @@ namespace {
     "  o.formatted_value = ?," \
     "  o.space = ?," \
     "  o.persistent = ?," \
+    "  o.cancelled = ?," \
     "  o.dhcp_client_class = ?," \
     "  o." #table_prefix "_subnet_id = ?," \
     "  o.scope_id = ?," \
index afaceced640c798839c5ff91ef7346b41a1b2be6..dfd5b2ae8277e67374539c1c6f9898f5458be0d8 100644 (file)
@@ -324,9 +324,9 @@ public:
                 auto rebind_timer = worker.getTriplet(11);
 
                 // valid_lifetime at 19.
-                // min_valid_lifetime at 53.
-                // max_valid_lifetime at 54.
-                auto valid_lifetime = worker.getTriplet(19, 53, 54);
+                // min_valid_lifetime at 55.
+                // max_valid_lifetime at 56.
+                auto valid_lifetime = worker.getTriplet(19, 55, 56);
 
                 // Create subnet with basic settings.
                 last_subnet = Subnet4::create(prefix_pair.first, prefix_pair.second,
@@ -422,86 +422,86 @@ public:
 
                 // valid_lifetime at 19 (fetched before subnet create).
 
-                // pool and option from 20 to 48.
+                // pool and options from 20 to 50.
 
-                // calculate_tee_times at 49.
-                if (!worker.isColumnNull(49)) {
-                    last_subnet->setCalculateTeeTimes(worker.getBool(49));
+                // calculate_tee_times at 51.
+                if (!worker.isColumnNull(51)) {
+                    last_subnet->setCalculateTeeTimes(worker.getBool(51));
                 }
 
-                // t1_percent at 50.
-                if (!worker.isColumnNull(50)) {
-                    last_subnet->setT1Percent(worker.getDouble(50));
+                // t1_percent at 52.
+                if (!worker.isColumnNull(52)) {
+                    last_subnet->setT1Percent(worker.getDouble(52));
                 }
 
-                // t2_percent at 51.
-                if (!worker.isColumnNull(51)) {
-                    last_subnet->setT2Percent(worker.getDouble(51));
+                // t2_percent at 53.
+                if (!worker.isColumnNull(53)) {
+                    last_subnet->setT2Percent(worker.getDouble(53));
                 }
 
-                // authoritative at 52.
-                if (!worker.isColumnNull(52)) {
-                    last_subnet->setAuthoritative(worker.getBool(52));
+                // authoritative at 54.
+                if (!worker.isColumnNull(54)) {
+                    last_subnet->setAuthoritative(worker.getBool(54));
                 }
 
-                // min_valid_lifetime at 53 (fetched as part of triplet).
-                // max_valid_lifetime at 54 (fetched as part of triplet).
+                // min_valid_lifetime at 55 (fetched as part of triplet).
+                // max_valid_lifetime at 56 (fetched as part of triplet).
 
                 // pool client_class, require_client_classes and user_context
-                // from 55 to 57.
-
-                // ddns_send_updates at 58.
-                if (!worker.isColumnNull(58)) {
-                    last_subnet->setDdnsSendUpdates(worker.getBool(58));
-                }
+                // from 57 to 59.
 
-                // ddns_override_no_update at 59.
-                if (!worker.isColumnNull(59)) {
-                    last_subnet->setDdnsOverrideNoUpdate(worker.getBool(59));
-                }
-
-                // ddns_override_client_update at 60.
+                // ddns_send_updates at 60.
                 if (!worker.isColumnNull(60)) {
-                    last_subnet->setDdnsOverrideClientUpdate(worker.getBool(60));
+                    last_subnet->setDdnsSendUpdates(worker.getBool(60));
                 }
 
-                // ddns_replace_client_name at 61.
+                // ddns_override_no_update at 61.
                 if (!worker.isColumnNull(61)) {
-                    last_subnet->setDdnsReplaceClientNameMode(
-                        static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(61)));
+                    last_subnet->setDdnsOverrideNoUpdate(worker.getBool(61));
                 }
 
-                // ddns_generated_prefix at 62.
+                // ddns_override_client_update at 62.
                 if (!worker.isColumnNull(62)) {
-                    last_subnet->setDdnsGeneratedPrefix(worker.getString(62));
+                    last_subnet->setDdnsOverrideClientUpdate(worker.getBool(62));
                 }
 
-                // ddns_qualifying_suffix at 63.
+                // ddns_replace_client_name at 63.
                 if (!worker.isColumnNull(63)) {
-                    last_subnet->setDdnsQualifyingSuffix(worker.getString(63));
+                    last_subnet->setDdnsReplaceClientNameMode(
+                        static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(63)));
                 }
 
-                // reservations_in_subnet at 64.
+                // ddns_generated_prefix at 64.
                 if (!worker.isColumnNull(64)) {
-                    last_subnet->setReservationsInSubnet(worker.getBool(64));
+                    last_subnet->setDdnsGeneratedPrefix(worker.getString(64));
                 }
 
-                // reservations_out_of_pool at 65.
+                // ddns_qualifying_suffix at 65.
                 if (!worker.isColumnNull(65)) {
-                    last_subnet->setReservationsOutOfPool(worker.getBool(65));
+                    last_subnet->setDdnsQualifyingSuffix(worker.getString(65));
                 }
 
-                // cache_threshold at 66.
+                // reservations_in_subnet at 66.
                 if (!worker.isColumnNull(66)) {
-                    last_subnet->setCacheThreshold(worker.getDouble(66));
+                    last_subnet->setReservationsInSubnet(worker.getBool(66));
                 }
 
-                // cache_max_age at 67.
+                // reservations_out_of_pool at 67.
                 if (!worker.isColumnNull(67)) {
-                    last_subnet->setCacheMaxAge(worker.getInt(67));
+                    last_subnet->setReservationsOutOfPool(worker.getBool(67));
+                }
+
+                // cache_threshold at 68.
+                if (!worker.isColumnNull(68)) {
+                    last_subnet->setCacheThreshold(worker.getDouble(68));
+                }
+
+                // cache_max_age at 69.
+                if (!worker.isColumnNull(69)) {
+                    last_subnet->setCacheMaxAge(worker.getInt(69));
                 }
 
-                // server_tag at 68.
+                // server_tag at 70.
 
                 // Subnet ready. Add it to the list.
                 auto ret = subnets.insert(last_subnet);
@@ -514,9 +514,9 @@ public:
                 }
             }
 
-            // Check for new server tags at 68.
-            if (!worker.isColumnNull(68)) {
-                std::string new_tag = worker.getString(68);
+            // Check for new server tags at 70.
+            if (!worker.isColumnNull(70)) {
+                std::string new_tag = worker.getString(70);
                 if (last_tag != new_tag) {
                     if (!new_tag.empty() && !last_subnet->hasServerTag(ServerTag(new_tag))) {
                         last_subnet->setServerTag(new_tag);
@@ -542,19 +542,19 @@ public:
                 last_pool = Pool4::create(IOAddress(worker.getInet4(21)),
                                           IOAddress(worker.getInet4(22)));
 
-                // pool client_class at 55.
-                if (!worker.isColumnNull(55)) {
-                    last_pool->allowClientClass(worker.getString(55));
+                // pool client_class at 57.
+                if (!worker.isColumnNull(57)) {
+                    last_pool->allowClientClass(worker.getString(57));
                 }
 
-                // pool require_client_classes at 56.
-                setRequiredClasses(worker, 56, [&last_pool](const std::string& class_name) {
+                // pool require_client_classes at 58.
+                setRequiredClasses(worker, 58, [&last_pool](const std::string& class_name) {
                     last_pool->requireClientClass(class_name);
                 });
 
-                // pool user_context at 57.
-                if (!worker.isColumnNull(57)) {
-                    ElementPtr user_context = worker.getJSON(57);
+                // pool user_context at 59.
+                if (!worker.isColumnNull(59)) {
+                    ElementPtr user_context = worker.getJSON(59);
                     if (user_context) {
                         last_pool->setContext(user_context);
                     }
@@ -563,7 +563,7 @@ public:
                 last_subnet->addPool(last_pool);
             }
 
-            // Parse pool-specific option from 25 to 36.
+            // Parse pool-specific option from 25 to 37.
             if (last_pool && !worker.isColumnNull(25) &&
                 (last_pool_option_id < worker.getBigInt(25))) {
                 last_pool_option_id = worker.getBigInt(25);
@@ -574,12 +574,12 @@ public:
                 }
             }
 
-            // Parse subnet-specific option from 37 to 48.
-            if (!worker.isColumnNull(37) &&
-                (last_option_id < worker.getBigInt(37))) {
-                last_option_id = worker.getBigInt(37);
+            // Parse subnet-specific option from 38 to 50.
+            if (!worker.isColumnNull(38) &&
+                (last_option_id < worker.getBigInt(38))) {
+                last_option_id = worker.getBigInt(38);
 
-                OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 37);
+                OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 38);
                 if (desc) {
                     last_subnet->getCfgOption()->add(*desc, desc->space_name_);
                 }
@@ -1232,104 +1232,104 @@ public:
                 }
 
                 // valid_lifetime at 12.
-                // min_valid_lifetime at 32.
-                // max_valid_lifetime at 33.
+                // min_valid_lifetime at 33.
+                // max_valid_lifetime at 34.
                 if (!worker.isColumnNull(12)) {
-                    last_network->setValid(worker.getTriplet(12, 32, 33));
+                    last_network->setValid(worker.getTriplet(12, 33, 34));
                 }
 
-                // option from 13 to 24.
-
-                // calculate_tee_times at 25.
-                if (!worker.isColumnNull(25)) {
-                    last_network->setCalculateTeeTimes(worker.getBool(25));
-                }
+                // option from 13 to 25.
 
-                // t1_percent at 26.
+                // calculate_tee_times at 26.
                 if (!worker.isColumnNull(26)) {
-                    last_network->setT1Percent(worker.getDouble(26));
+                    last_network->setCalculateTeeTimes(worker.getBool(26));
                 }
 
-                // t2_percent at 27.
+                // t1_percent at 27.
                 if (!worker.isColumnNull(27)) {
-                    last_network->setT2Percent(worker.getDouble(27));
+                    last_network->setT1Percent(worker.getDouble(27));
                 }
 
-                // authoritative at 28.
+                // t2_percent at 28.
                 if (!worker.isColumnNull(28)) {
-                    last_network->setAuthoritative(worker.getBool(28));
+                    last_network->setT2Percent(worker.getDouble(28));
                 }
 
-                // boot_file_name at 29.
+                // authoritative at 29.
                 if (!worker.isColumnNull(29)) {
-                    last_network->setFilename(worker.getString(29));
+                    last_network->setAuthoritative(worker.getBool(29));
                 }
 
-                // next_server at 30.
+                // boot_file_name at 30.
                 if (!worker.isColumnNull(30)) {
-                    last_network->setSiaddr(worker.getInet4(30));
+                    last_network->setFilename(worker.getString(30));
                 }
 
-                // server_hostname at 31.
+                // next_server at 31.
                 if (!worker.isColumnNull(31)) {
-                    last_network->setSname(worker.getString(31));
+                    last_network->setSiaddr(worker.getInet4(31));
                 }
 
-                // min_valid_lifetime at 32.
-                // max_valid_lifetime at 33.
-
-                // ddns_send_updates at 34.
-                if (!worker.isColumnNull(34)) {
-                    last_network->setDdnsSendUpdates(worker.getBool(34));
+                // server_hostname at 32.
+                if (!worker.isColumnNull(32)) {
+                    last_network->setSname(worker.getString(32));
                 }
 
-                // ddns_override_no_update at 35.
+                // min_valid_lifetime at 33.
+                // max_valid_lifetime at 34.
+
+                // ddns_send_updates at 35.
                 if (!worker.isColumnNull(35)) {
-                    last_network->setDdnsOverrideNoUpdate(worker.getBool(35));
+                    last_network->setDdnsSendUpdates(worker.getBool(35));
                 }
 
-                // ddns_override_client_update at 36.
+                // ddns_override_no_update at 36.
                 if (!worker.isColumnNull(36)) {
-                    last_network->setDdnsOverrideClientUpdate(worker.getBool(36));
+                    last_network->setDdnsOverrideNoUpdate(worker.getBool(36));
                 }
 
-                // ddns_replace_client_name at 37.
+                // ddns_override_client_update at 37.
                 if (!worker.isColumnNull(37)) {
-                    last_network->setDdnsReplaceClientNameMode(
-                        static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(37)));
+                    last_network->setDdnsOverrideClientUpdate(worker.getBool(37));
                 }
 
-                // ddns_generated_prefix at 38.
+                // ddns_replace_client_name at 38.
                 if (!worker.isColumnNull(38)) {
-                    last_network->setDdnsGeneratedPrefix(worker.getString(38));
+                    last_network->setDdnsReplaceClientNameMode(
+                        static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(38)));
                 }
 
-                // ddns_qualifying_suffix at 39.
+                // ddns_generated_prefix at 39.
                 if (!worker.isColumnNull(39)) {
-                    last_network->setDdnsQualifyingSuffix(worker.getString(39));
+                    last_network->setDdnsGeneratedPrefix(worker.getString(39));
                 }
 
-                // reservations_in_subnet at 40.
+                // ddns_qualifying_suffix at 40.
                 if (!worker.isColumnNull(40)) {
-                    last_network->setReservationsInSubnet(worker.getBool(40));
+                    last_network->setDdnsQualifyingSuffix(worker.getString(40));
                 }
 
                 // reservations_in_subnet at 41.
                 if (!worker.isColumnNull(41)) {
-                    last_network->setReservationsOutOfPool(worker.getBool(41));
+                    last_network->setReservationsInSubnet(worker.getBool(41));
                 }
 
-                // cache_threshold at 42.
+                // reservations_in_subnet at 42.
                 if (!worker.isColumnNull(42)) {
-                    last_network->setCacheThreshold(worker.getDouble(42));
+                    last_network->setReservationsOutOfPool(worker.getBool(42));
                 }
 
-                // cache_max_age at 43.
+                // cache_threshold at 43.
                 if (!worker.isColumnNull(43)) {
-                    last_network->setCacheMaxAge(worker.getInt(43));
+                    last_network->setCacheThreshold(worker.getDouble(43));
                 }
 
-                // server_tag at 44.
+                // cache_max_age at 44.
+                if (!worker.isColumnNull(44)) {
+                    last_network->setCacheMaxAge(worker.getInt(44));
+                }
+
+                // server_tag at 45.
 
                 // Add the shared network.
                 auto ret = shared_networks.push_back(last_network);
@@ -1343,8 +1343,8 @@ public:
             }
 
             // Check for new server tags.
-            if (!worker.isColumnNull(44)) {
-                std::string new_tag = worker.getString(44);
+            if (!worker.isColumnNull(45)) {
+                std::string new_tag = worker.getString(45);
                 if (last_tag != new_tag) {
                     if (!new_tag.empty() && !last_network->hasServerTag(ServerTag(new_tag))) {
                         last_network->setServerTag(new_tag);
@@ -1354,7 +1354,7 @@ public:
                 }
             }
 
-            // Parse network-specific option from 13 to 24.
+            // Parse network-specific option from 13 to 25.
             if (!worker.isColumnNull(13) &&
                 (last_option_id < worker.getBigInt(13))) {
                 last_option_id = worker.getBigInt(13);
@@ -1610,6 +1610,7 @@ public:
         in_bindings.addOptional(option->formatted_value_);
         in_bindings.addOptional(option->space_name_);
         in_bindings.add(option->persistent_);
+        in_bindings.add(option->cancelled_);
         in_bindings.addNull();
         in_bindings.addNull();
         in_bindings.add(0);
@@ -1677,6 +1678,7 @@ public:
         in_bindings.addOptional(option->formatted_value_);
         in_bindings.addOptional(option->space_name_);
         in_bindings.add(option->persistent_);
+        in_bindings.add(option->cancelled_);
         in_bindings.addNull();
         in_bindings.add(subnet_id);
         in_bindings.add(1);
@@ -1767,6 +1769,7 @@ public:
         in_bindings.addOptional(option->formatted_value_);
         in_bindings.addOptional(option->space_name_);
         in_bindings.add(option->persistent_);
+        in_bindings.add(option->cancelled_);
         in_bindings.addNull();
         in_bindings.addNull();
         in_bindings.add(5);
@@ -1836,6 +1839,7 @@ public:
         in_bindings.addOptional(option->formatted_value_);
         in_bindings.addOptional(option->space_name_);
         in_bindings.add(option->persistent_);
+        in_bindings.add(option->cancelled_);
         in_bindings.addNull();
         in_bindings.addNull();
         in_bindings.add(4);
@@ -1901,6 +1905,7 @@ public:
         in_bindings.addOptional(option->formatted_value_);
         in_bindings.addOptional(option->space_name_);
         in_bindings.add(option->persistent_);
+        in_bindings.add(option->cancelled_);
         in_bindings.add(class_name);
         in_bindings.addNull();
         in_bindings.add(2);
@@ -2269,9 +2274,9 @@ public:
                 class_list.push_back(last_client_class);
             }
 
-            // Check for new server tags at 36.
-            if (!worker.isColumnNull(36)) {
-                std::string new_tag = worker.getString(36);
+            // Check for new server tags at 37.
+            if (!worker.isColumnNull(37)) {
+                std::string new_tag = worker.getString(37);
                 if (last_tag != new_tag) {
                     if (!new_tag.empty() && !last_client_class->hasServerTag(ServerTag(new_tag))) {
                         last_client_class->setServerTag(new_tag);
@@ -2292,7 +2297,7 @@ public:
                 }
             }
 
-            // Parse client class specific option from 24 to 35.
+            // Parse client class specific option from 24 to 36.
             if (!worker.isColumnNull(24) &&
                 (last_option_id < worker.getBigInt(24))) {
                 last_option_id = worker.getBigInt(24);
@@ -3533,20 +3538,21 @@ TaggedStatementArray tagged_statements = { {
     // Insert subnet specific option.
     {
         // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION4,
-        12,
+        13,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp4_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP   // 12 modification_ts
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp4_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP   // 13 modification_ts
         },
         "INSERT_OPTION4",
         PGSQL_INSERT_OPTION4()
@@ -3866,126 +3872,131 @@ TaggedStatementArray tagged_statements = { {
     // Update existing global option.
     {
         // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4,
-        15,
+        16,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp4_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_VARCHAR,    // 13 server_tag
-            OID_INT2,       // 14 code (of option to update)
-            OID_VARCHAR,    // 15 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp4_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_VARCHAR,    // 14 server_tag
+            OID_INT2,       // 15 code (of option to update)
+            OID_VARCHAR,    // 16 space (of option to update)
         },
         "UPDATE_OPTION4",
-        PGSQL_UPDATE_OPTION4_WITH_TAG(AND o.scope_id = 0 AND o.code = $14 AND o.space = $15)
+        PGSQL_UPDATE_OPTION4_WITH_TAG(AND o.scope_id = 0 AND o.code = $15 AND o.space = $16)
     },
 
     // Update existing subnet level option.
     {
         // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SUBNET_ID,
-        15,
+        16,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp4_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_INT8,       // 13 subnet_id (of option to update)
-            OID_INT2,       // 14 code (of option to update)
-            OID_VARCHAR     // 15 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp4_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_INT8,       // 14 subnet_id (of option to update)
+            OID_INT2,       // 15 code (of option to update)
+            OID_VARCHAR     // 16 space (of option to update)
         },
         "UPDATE_OPTION4_SUBNET_ID",
-        PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 1 AND o.dhcp4_subnet_id = $13 AND o.code = $14 AND o.space = $15)
+        PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 1 AND o.dhcp4_subnet_id = $14 AND o.code = $15 AND o.space = $16)
     },
 
     // Update existing pool level option.
     {
         // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_POOL_ID,
-        15,
+        16,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp4_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_INT8,       // 13 pool_id (of option to update)
-            OID_INT2,       // 14 code (of option to update)
-            OID_VARCHAR     // 15 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp4_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_INT8,       // 14 pool_id (of option to update)
+            OID_INT2,       // 15 code (of option to update)
+            OID_VARCHAR     // 16 space (of option to update)
         },
         "UPDATE_OPTION4_POOL_ID",
-        PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 5 AND o.pool_id = $13 AND o.code = $14 AND o.space = $15)
+        PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 5 AND o.pool_id = $14 AND o.code = $15 AND o.space = $16)
     },
 
     // Update existing shared network level option.
     {
         // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SHARED_NETWORK,
-        15,
+        16,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp4_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_VARCHAR,    // 13 shared_network_name (of option to update)
-            OID_INT2,       // 14 code (of option to update)
-            OID_VARCHAR     // 15 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp4_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_VARCHAR,    // 14 shared_network_name (of option to update)
+            OID_INT2,       // 15 code (of option to update)
+            OID_VARCHAR     // 16 space (of option to update)
         },
         "UPDATE_OPTION4_SHARED_NETWORK",
-        PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 4 AND o.shared_network_name = $13 AND o.code = $14 AND o.space = $15)
+        PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 4 AND o.shared_network_name = $14 AND o.code = $15 AND o.space = $16)
     },
 
     // Update existing client class level option.
     {
         // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_CLIENT_CLASS,
-        15,
+        16,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp4_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_VARCHAR,    // 13 dhcp_client_class (of option to update)
-            OID_INT2,       // 14 code (of option to update)
-            OID_VARCHAR,    // 15 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp4_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_VARCHAR,    // 14 dhcp_client_class (of option to update)
+            OID_INT2,       // 15 code (of option to update)
+            OID_VARCHAR,    // 16 space (of option to update)
         },
         "UPDATE_OPTION4_CLIENT_CLASS",
-        PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = $13 AND o.code = $14 AND o.space = $15)
+        PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = $14 AND o.code = $15 AND o.space = $16)
     },
 
     // Update existing client class with specifying its position.
index acf6e4aa20ab43b0716f5b5d916b3b6334b906da..12dbfc09975068f753f9b63cbf8543ca32c65fa3 100644 (file)
@@ -335,9 +335,9 @@ public:
                 auto prefix_pair = Subnet6::parsePrefix(subnet_prefix);
 
                 // preferred_lifetime (5)
-                // min_preferred_lifetime (69)
-                // max_preferred_lifetime (70)
-                auto preferred_lifetime = worker.getTriplet(5, 69, 70);
+                // min_preferred_lifetime (72)
+                // max_preferred_lifetime (73)
+                auto preferred_lifetime = worker.getTriplet(5, 72, 73);
 
                 // renew_timer at 9.
                 auto renew_timer = worker.getTriplet(9);
@@ -346,9 +346,9 @@ public:
                 auto rebind_timer = worker.getTriplet(7);
 
                 // valid_lifetime at 14.
-                // min_valid_lifetime at 71.
-                // max_valid_lifetime at 72.
-                auto valid_lifetime = worker.getTriplet(14, 71, 72);
+                // min_valid_lifetime at 74.
+                // max_valid_lifetime at 75.
+                auto valid_lifetime = worker.getTriplet(14, 74, 75);
 
                 // Create subnet with basic settings.
                 last_subnet = Subnet6::create(prefix_pair.first, prefix_pair.second,
@@ -411,93 +411,93 @@ public:
 
                 // 15 to 19 are pool
                 // 20 to 25 are pd pool
-                // 26 to 38 are pool option
-                // 39 to 51 are pd pool option
-                // 52 to 64 are option
+                // 26 to 39 are pool option
+                // 40 to 53 are pd pool option
+                // 54 to 67 are option
 
-                // calculate_tee_times at 65.
-                if (!worker.isColumnNull(65)) {
-                    last_subnet->setCalculateTeeTimes(worker.getBool(65));
+                // calculate_tee_times at 68.
+                if (!worker.isColumnNull(68)) {
+                    last_subnet->setCalculateTeeTimes(worker.getBool(68));
                 }
 
-                // t1_percent at 66.
-                if (!worker.isColumnNull(66)) {
-                    last_subnet->setT1Percent(worker.getDouble(66));
+                // t1_percent at 69.
+                if (!worker.isColumnNull(69)) {
+                    last_subnet->setT1Percent(worker.getDouble(69));
                 }
 
-                // t2_percent at 67.
-                if (!worker.isColumnNull(67)) {
-                    last_subnet->setT2Percent(worker.getDouble(67));
+                // t2_percent at 70.
+                if (!worker.isColumnNull(70)) {
+                    last_subnet->setT2Percent(worker.getDouble(70));
                 }
 
-                // interface_id at 68.
-                setInterfaceId(*last_subnet, worker, 68);
+                // interface_id at 71.
+                setInterfaceId(*last_subnet, worker, 71);
 
-                // 69 and 70 are {min,max}_preferred_lifetime
+                // 72 and 73 are {min,max}_preferred_lifetime
 
-                // 71 and 72 are {min,max}_valid_lifetime
+                // 74 and 75 are {min,max}_valid_lifetime
 
-                // 73 is pool client_class
-                // 74 is pool require_client_classes
-                // 75 is pool user_context
-                // 76 is pd pool excluded_prefix
-                // 77 is pd pool excluded_prefix_length
-                // 78 is pd pool client_class
-                // 79 is pd pool require_client_classes
-                // 80 is pd pool user_context
+                // 76 is pool client_class
+                // 77 is pool require_client_classes
+                // 78 is pool user_context
+                // 79 is pd pool excluded_prefix
+                // 80 is pd pool excluded_prefix_length
+                // 81 is pd pool client_class
+                // 82 is pd pool require_client_classes
+                // 83 is pd pool user_context
 
-                // ddns_send_updates at 81.
-                if (!worker.isColumnNull(81)) {
-                    last_subnet->setDdnsSendUpdates(worker.getBool(81));
-                }
-
-                // ddns_override_no_update at 82.
-                if (!worker.isColumnNull(82)) {
-                    last_subnet->setDdnsOverrideNoUpdate(worker.getBool(82));
-                }
-
-                // ddns_override_client_update at 83.
-                if (!worker.isColumnNull(83)) {
-                    last_subnet->setDdnsOverrideClientUpdate(worker.getBool(83));
-                }
-
-                // ddns_replace_client_name at 84.
+                // ddns_send_updates at 84.
                 if (!worker.isColumnNull(84)) {
-                    last_subnet->setDdnsReplaceClientNameMode(
-                        static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(84)));
+                    last_subnet->setDdnsSendUpdates(worker.getBool(84));
                 }
 
-                // ddns_generated_prefix at 85.
+                // ddns_override_no_update at 85.
                 if (!worker.isColumnNull(85)) {
-                    last_subnet->setDdnsGeneratedPrefix(worker.getString(85));
+                    last_subnet->setDdnsOverrideNoUpdate(worker.getBool(85));
                 }
 
-                // ddns_qualifying_suffix at 86.
+                // ddns_override_client_update at 86.
                 if (!worker.isColumnNull(86)) {
-                    last_subnet->setDdnsQualifyingSuffix(worker.getString(86));
+                    last_subnet->setDdnsOverrideClientUpdate(worker.getBool(86));
                 }
 
-                // reservations_in_subnet at 87.
+                // ddns_replace_client_name at 87.
                 if (!worker.isColumnNull(87)) {
-                    last_subnet->setReservationsInSubnet(worker.getBool(87));
+                    last_subnet->setDdnsReplaceClientNameMode(
+                        static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(87)));
                 }
 
-                // reservations_out_of_pool at 88.
+                // ddns_generated_prefix at 88.
                 if (!worker.isColumnNull(88)) {
-                    last_subnet->setReservationsOutOfPool(worker.getBool(88));
+                    last_subnet->setDdnsGeneratedPrefix(worker.getString(88));
                 }
 
-                // cache_threshold at 89.
+                // ddns_qualifying_suffix at 89.
                 if (!worker.isColumnNull(89)) {
-                    last_subnet->setCacheThreshold(worker.getDouble(89));
+                    last_subnet->setDdnsQualifyingSuffix(worker.getString(89));
                 }
 
-                // cache_max_age at 90.
+                // reservations_in_subnet at 90.
                 if (!worker.isColumnNull(90)) {
-                    last_subnet->setCacheMaxAge(worker.getInt(90));
+                    last_subnet->setReservationsInSubnet(worker.getBool(90));
                 }
 
-                // server_tag at 91.
+                // reservations_out_of_pool at 91.
+                if (!worker.isColumnNull(91)) {
+                    last_subnet->setReservationsOutOfPool(worker.getBool(91));
+                }
+
+                // cache_threshold at 92.
+                if (!worker.isColumnNull(92)) {
+                    last_subnet->setCacheThreshold(worker.getDouble(92));
+                }
+
+                // cache_max_age at 93.
+                if (!worker.isColumnNull(93)) {
+                    last_subnet->setCacheMaxAge(worker.getInt(93));
+                }
+
+                // server_tag at 94.
 
                 // Subnet ready. Add it to the list.
                 auto ret = subnets.insert(last_subnet);
@@ -510,9 +510,9 @@ public:
                 }
             }
 
-            // Check for new server tags at 91.
-            if (!worker.isColumnNull(91)) {
-                std::string new_tag = worker.getString(91);
+            // Check for new server tags at 94.
+            if (!worker.isColumnNull(94)) {
+                std::string new_tag = worker.getString(94);
                 if (last_tag != new_tag) {
                     if (!new_tag.empty() && !last_subnet->hasServerTag(ServerTag(new_tag))) {
                         last_subnet->setServerTag(new_tag);
@@ -522,7 +522,7 @@ public:
                 }
             }
 
-            // Pool is between 15 and 19 with extra between 73 and 75
+            // Pool is between 15 and 19 with extra between 76 and 78
 
             // If the row contains information about the pool and it
             // appears to be new pool entry (checked by comparing pool
@@ -543,19 +543,19 @@ public:
                 // pool subnet_id at 18 (ignored)
                 // pool modification_ts at 19 (ignored)
 
-                // pool client_class at 73.
-                if (!worker.isColumnNull(73)) {
-                    last_pool->allowClientClass(worker.getString(73));
+                // pool client_class at 76.
+                if (!worker.isColumnNull(76)) {
+                    last_pool->allowClientClass(worker.getString(76));
                 }
 
-                // pool require_client_classes at 74.
-                setRequiredClasses(worker, 74, [&last_pool](const std::string& class_name) {
+                // pool require_client_classes at 77.
+                setRequiredClasses(worker, 77, [&last_pool](const std::string& class_name) {
                     last_pool->requireClientClass(class_name);
                 });
 
-                // pool user_context at 75.
-                if (!worker.isColumnNull(75)) {
-                    ElementPtr user_context = worker.getJSON(75);
+                // pool user_context at 78.
+                if (!worker.isColumnNull(78)) {
+                    ElementPtr user_context = worker.getJSON(78);
                     if (user_context) {
                         last_pool->setContext(user_context);
                     }
@@ -564,7 +564,7 @@ public:
                 last_subnet->addPool(last_pool);
             }
 
-            // Pd Pool is between 20 and 25 with extra between 76 and 80
+            // Pd Pool is between 20 and 25 with extra between 79 and 83
 
             // If the row contains information about the pd pool and
             // it appears to be new pd pool entry (checked by
@@ -583,10 +583,10 @@ public:
                 // 24 is pd pool subnet_id (ignored)
                 // 25 is pd pool modification_ts (ignored)
 
-                // excluded_prefix (76) and excluded_prefix_length (77)
+                // excluded_prefix (79) and excluded_prefix_length (80)
                 IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS();
-                if (!worker.isColumnNull(76)) {
-                    excluded_prefix = worker.getInet6(76);
+                if (!worker.isColumnNull(79)) {
+                    excluded_prefix = worker.getInet6(79);
                 }
 
                 last_pd_pool_id = worker.getBigInt(20);
@@ -594,21 +594,21 @@ public:
                                              static_cast<uint8_t>(worker.getSmallInt(22)),
                                              static_cast<uint8_t>(worker.getSmallInt(23)),
                                              excluded_prefix,
-                                             static_cast<uint8_t>(worker.getSmallInt(77)));
+                                             static_cast<uint8_t>(worker.getSmallInt(80)));
 
-                // pd pool client_class (78)
-                if (!worker.isColumnNull(78)) {
-                    last_pd_pool->allowClientClass(worker.getString(78));
+                // pd pool client_class (81)
+                if (!worker.isColumnNull(81)) {
+                    last_pd_pool->allowClientClass(worker.getString(81));
                 }
 
-                // pd pool require_client_classes at 79.
-                setRequiredClasses(worker, 79, [&last_pd_pool](const std::string& class_name) {
+                // pd pool require_client_classes at 82.
+                setRequiredClasses(worker, 82, [&last_pd_pool](const std::string& class_name) {
                     last_pd_pool->requireClientClass(class_name);
                 });
 
-                // pd pool user_context at 80.
-                if (!worker.isColumnNull(80)) {
-                    ElementPtr user_context = worker.getJSON(80);
+                // pd pool user_context at 83.
+                if (!worker.isColumnNull(83)) {
+                    ElementPtr user_context = worker.getJSON(83);
                     if (user_context) {
                         last_pd_pool->setContext(user_context);
                     }
@@ -617,7 +617,7 @@ public:
                 last_subnet->addPool(last_pd_pool);
             }
 
-            // Parse pool-specific option from 26 to 38.
+            // Parse pool-specific option from 26 to 39.
             if (last_pool && !worker.isColumnNull(26) &&
                 (last_pool_option_id < worker.getBigInt(26))) {
                 last_pool_option_id = worker.getBigInt(26);
@@ -628,23 +628,23 @@ public:
                 }
             }
 
-            // Parse pd pool-specific option from 39 to 51.
-            if (last_pd_pool && !worker.isColumnNull(39) &&
-                (last_pd_pool_option_id < worker.getBigInt(39))) {
-                last_pd_pool_option_id = worker.getBigInt(39);
+            // Parse pd pool-specific option from 40 to 53.
+            if (last_pd_pool && !worker.isColumnNull(40) &&
+                (last_pd_pool_option_id < worker.getBigInt(40))) {
+                last_pd_pool_option_id = worker.getBigInt(40);
 
-                OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 39);
+                OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 40);
                 if (desc) {
                     last_pd_pool->getCfgOption()->add(*desc, desc->space_name_);
                 }
             }
 
-            // Parse subnet-specific option from 52 to 64.
-            if (!worker.isColumnNull(52) &&
-                (last_option_id < worker.getBigInt(52))) {
-                last_option_id = worker.getBigInt(52);
+            // Parse subnet-specific option from 54 to 67.
+            if (!worker.isColumnNull(54) &&
+                (last_option_id < worker.getBigInt(54))) {
+                last_option_id = worker.getBigInt(54);
 
-                OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 52);
+                OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 54);
                 if (desc) {
                     last_subnet->getCfgOption()->add(*desc, desc->space_name_);
                 }
@@ -928,7 +928,7 @@ public:
                 pd_pool_ids.push_back(last_pd_pool_id);
             }
 
-            // Parse pd pool specific option between 11 and 24.
+            // Parse pd pool specific option between 11 and 25.
             if (last_pd_pool && !worker.isColumnNull(11) &&
                 (last_pd_pool_option_id < worker.getBigInt(11))) {
                 last_pd_pool_option_id = worker.getBigInt(11);
@@ -1443,9 +1443,9 @@ public:
                 last_network->setModificationTime(worker.getTimestamp(4));
 
                 // preferred_lifetime (5)
-                // min_preferred_lifetime (31)
-                // max_preferred_lifetime (32)
-                last_network->setPreferred(worker.getTriplet(5, 31, 32));
+                // min_preferred_lifetime (32)
+                // max_preferred_lifetime (33)
+                last_network->setPreferred(worker.getTriplet(5, 32, 33));
 
                 // rapid_commit at 6.
                 if (!worker.isColumnNull(6)) {
@@ -1484,89 +1484,89 @@ public:
                 }
 
                 // valid_lifetime at 13.
-                // min_valid_lifetime at 33.
-                // max_valid_lifetime at 34.
+                // min_valid_lifetime at 34.
+                // max_valid_lifetime at 35.
                 if (!worker.isColumnNull(13)) {
-                    last_network->setValid(worker.getTriplet(13, 33, 34));
+                    last_network->setValid(worker.getTriplet(13, 34, 35));
                 }
 
-                // option from 14 to 26.
-
-                // calculate_tee_times at 27.
-                if (!worker.isColumnNull(27)) {
-                    last_network->setCalculateTeeTimes(worker.getBool(27));
-                }
+                // option from 14 to 27.
 
-                // t1_percent at 28.
+                // calculate_tee_times at 28.
                 if (!worker.isColumnNull(28)) {
-                    last_network->setT1Percent(worker.getDouble(28));
+                    last_network->setCalculateTeeTimes(worker.getBool(28));
                 }
 
-                // t2_percent at 29.
+                // t1_percent at 29.
                 if (!worker.isColumnNull(29)) {
-                    last_network->setT2Percent(worker.getDouble(29));
+                    last_network->setT1Percent(worker.getDouble(29));
                 }
 
-                // interface_id at 30.
-                setInterfaceId(*last_network, worker, 30);
+                // t2_percent at 30.
+                if (!worker.isColumnNull(30)) {
+                    last_network->setT2Percent(worker.getDouble(30));
+                }
 
-                // min_preferred_lifetime at 31.
-                // max_preferred_lifetime at 32.
-                // min_valid_lifetime at 33.
-                // max_valid_lifetime at 34.
+                // interface_id at 31.
+                setInterfaceId(*last_network, worker, 31);
 
-                // ddns_send_updates at 35.
-                if (!worker.isColumnNull(35)) {
-                    last_network->setDdnsSendUpdates(worker.getBool(35));
-                }
+                // min_preferred_lifetime at 32.
+                // max_preferred_lifetime at 33.
+                // min_valid_lifetime at 34.
+                // max_valid_lifetime at 35.
 
-                // ddns_override_no_update at 36.
+                // ddns_send_updates at 36.
                 if (!worker.isColumnNull(36)) {
-                    last_network->setDdnsOverrideNoUpdate(worker.getBool(36));
+                    last_network->setDdnsSendUpdates(worker.getBool(36));
                 }
 
-                // ddns_override_client_update at 37.
+                // ddns_override_no_update at 37.
                 if (!worker.isColumnNull(37)) {
-                    last_network->setDdnsOverrideClientUpdate(worker.getBool(37));
+                    last_network->setDdnsOverrideNoUpdate(worker.getBool(37));
                 }
 
-                // ddns_replace_client_name at 38.
+                // ddns_override_client_update at 38.
                 if (!worker.isColumnNull(38)) {
-                    last_network->setDdnsReplaceClientNameMode(
-                        static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(38)));
+                    last_network->setDdnsOverrideClientUpdate(worker.getBool(38));
                 }
 
-                // ddns_generated_prefix at 39.
+                // ddns_replace_client_name at 39.
                 if (!worker.isColumnNull(39)) {
-                    last_network->setDdnsGeneratedPrefix(worker.getString(39));
+                    last_network->setDdnsReplaceClientNameMode(
+                        static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(39)));
                 }
 
-                // ddns_qualifying_suffix at 40.
+                // ddns_generated_prefix at 40.
                 if (!worker.isColumnNull(40)) {
-                    last_network->setDdnsQualifyingSuffix(worker.getString(40));
+                    last_network->setDdnsGeneratedPrefix(worker.getString(40));
                 }
 
-                // reservations_in_subnet at 41.
+                // ddns_qualifying_suffix at 41.
                 if (!worker.isColumnNull(41)) {
-                    last_network->setReservationsInSubnet(worker.getBool(41));
+                    last_network->setDdnsQualifyingSuffix(worker.getString(41));
                 }
 
                 // reservations_in_subnet at 42.
                 if (!worker.isColumnNull(42)) {
-                    last_network->setReservationsOutOfPool(worker.getBool(42));
+                    last_network->setReservationsInSubnet(worker.getBool(42));
                 }
 
-                // cache_threshold at 43.
+                // reservations_in_subnet at 43.
                 if (!worker.isColumnNull(43)) {
-                    last_network->setCacheThreshold(worker.getDouble(43));
+                    last_network->setReservationsOutOfPool(worker.getBool(43));
                 }
 
-                // cache_max_age at 44.
+                // cache_threshold at 44.
                 if (!worker.isColumnNull(44)) {
-                    last_network->setCacheMaxAge(worker.getInt(44));
+                    last_network->setCacheThreshold(worker.getDouble(44));
+                }
+
+                // cache_max_age at 45.
+                if (!worker.isColumnNull(45)) {
+                    last_network->setCacheMaxAge(worker.getInt(45));
                 }
 
-                // server_tag at 45.
+                // server_tag at 46.
 
                 // Add the shared network.
                 auto ret = shared_networks.push_back(last_network);
@@ -1580,8 +1580,8 @@ public:
             }
 
             // Check for new server tags.
-            if (!worker.isColumnNull(45)) {
-                std::string new_tag = worker.getString(45);
+            if (!worker.isColumnNull(46)) {
+                std::string new_tag = worker.getString(46);
                 if (last_tag != new_tag) {
                     if (!new_tag.empty() && !last_network->hasServerTag(ServerTag(new_tag))) {
                         last_network->setServerTag(new_tag);
@@ -1591,7 +1591,7 @@ public:
                 }
             }
 
-            // Parse network-specific option from 14 to 26.
+            // Parse network-specific option from 14 to 27.
             if (!worker.isColumnNull(14) &&
                 (last_option_id < worker.getBigInt(14))) {
                 last_option_id = worker.getBigInt(14);
@@ -1847,6 +1847,7 @@ public:
         in_bindings.addOptional(option->formatted_value_);
         in_bindings.addOptional(option->space_name_);
         in_bindings.add(option->persistent_);
+        in_bindings.add(option->cancelled_);
         in_bindings.addNull();
         in_bindings.addNull();
         in_bindings.add(0);
@@ -1915,6 +1916,7 @@ public:
         in_bindings.addOptional(option->formatted_value_);
         in_bindings.addOptional(option->space_name_);
         in_bindings.add(option->persistent_);
+        in_bindings.add(option->cancelled_);
         in_bindings.addNull();
         in_bindings.add(subnet_id);
         in_bindings.add(1);
@@ -2044,6 +2046,7 @@ public:
         in_bindings.addOptional(option->formatted_value_);
         in_bindings.addOptional(option->space_name_);
         in_bindings.add(option->persistent_);
+        in_bindings.add(option->cancelled_);
         in_bindings.addNull();
         in_bindings.addNull();
 
@@ -2142,6 +2145,7 @@ public:
         in_bindings.addOptional(option->formatted_value_);
         in_bindings.addOptional(option->space_name_);
         in_bindings.add(option->persistent_);
+        in_bindings.add(option->cancelled_);
         in_bindings.addNull();
         in_bindings.addNull();
         in_bindings.add(4);
@@ -2208,6 +2212,7 @@ public:
         in_bindings.addOptional(option->formatted_value_);
         in_bindings.addOptional(option->space_name_);
         in_bindings.add(option->persistent_);
+        in_bindings.add(option->cancelled_);
         in_bindings.add(class_name);
         in_bindings.addNull();
         in_bindings.add(2);
@@ -2588,17 +2593,17 @@ public:
                 }
 
                 // class specific option definition from 11 to 20.
-                // class specific option from 21 to 32.
+                // class specific option from 21 to 33.
 
                 // preferred lifetime: default, min, max
-                last_client_class->setPreferred(worker.getTriplet(34, 35, 36));
+                last_client_class->setPreferred(worker.getTriplet(35, 36, 37));
 
                 class_list.push_back(last_client_class);
             }
 
-            // Check for new server tags at 33.
-            if (!worker.isColumnNull(33)) {
-                std::string new_tag = worker.getString(33);
+            // Check for new server tags at 34.
+            if (!worker.isColumnNull(34)) {
+                std::string new_tag = worker.getString(34);
                 if (last_tag != new_tag) {
                     if (!new_tag.empty() && !last_client_class->hasServerTag(ServerTag(new_tag))) {
                         last_client_class->setServerTag(new_tag);
@@ -2619,7 +2624,7 @@ public:
                 }
             }
 
-            // Parse client class specific option from 21 to 32.
+            // Parse client class specific option from 21 to 33.
             if (!worker.isColumnNull(21) &&
                 (last_option_id < worker.getBigInt(21))) {
                 last_option_id = worker.getBigInt(21);
@@ -3953,21 +3958,22 @@ TaggedStatementArray tagged_statements = { {
     // Insert subnet specific option.
     {
         // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION6,
-        13,
+        14,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp6_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_INT8        // 13 pd_pool_id
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp6_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_INT8        // 14 pd_pool_id
         },
         "INSERT_OPTION6",
         PGSQL_INSERT_OPTION6()
@@ -4278,157 +4284,163 @@ TaggedStatementArray tagged_statements = { {
     // Update existing global option.
     {
         // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6,
-        16,
+        17,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp6_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_INT8,       // 13 pd_pool_id
-            OID_VARCHAR,    // 14 server_tag
-            OID_INT2,       // 15 code (of option to update)
-            OID_VARCHAR,    // 16 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp6_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_INT8,       // 14 pd_pool_id
+            OID_VARCHAR,    // 15 server_tag
+            OID_INT2,       // 16 code (of option to update)
+            OID_VARCHAR,    // 17 space (of option to update)
         },
         "UPDATE_OPTION6",
-        PGSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = $15 AND o.space = $16)
+        PGSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = $16 AND o.space = $17)
     },
 
     // Update existing subnet level option.
     {
         // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID,
-        16,
+        17,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp6_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_INT8,       // 13 pd_pool_id
-            OID_INT8,       // 14 subnet_id (of option to update)
-            OID_INT2,       // 15 code (of option to update)
-            OID_VARCHAR     // 16 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp6_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_INT8,       // 14 pd_pool_id
+            OID_INT8,       // 15 subnet_id (of option to update)
+            OID_INT2,       // 16 code (of option to update)
+            OID_VARCHAR     // 17 space (of option to update)
         },
         "UPDATE_OPTION6_SUBNET_ID",
-        PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 1 AND o.dhcp6_subnet_id = $14 AND o.code = $15 AND o.space = $16)
+        PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 1 AND o.dhcp6_subnet_id = $15 AND o.code = $16 AND o.space = $17)
     },
 
     // Update existing pool level option.
     {
         // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID,
-        16,
+        17,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp6_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_INT8,       // 13 pd_pool_id
-            OID_INT8,       // 14 pool_id (of option to update)
-            OID_INT2,       // 15 code (of option to update)
-            OID_VARCHAR     // 16 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp6_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_INT8,       // 14 pd_pool_id
+            OID_INT8,       // 15 pool_id (of option to update)
+            OID_INT2,       // 16 code (of option to update)
+            OID_VARCHAR     // 17 space (of option to update)
         },
         "UPDATE_OPTION6_POOL_ID",
-        PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 5 AND o.pool_id = $14 AND o.code = $15 AND o.space = $16)
+        PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 5 AND o.pool_id = $15 AND o.code = $16 AND o.space = $17)
     },
 
     // Update existing pd pool level option.
     {
         // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID,
-        16,
+        17,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp6_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_INT8,       // 13 pd_pool_id
-            OID_INT8,       // 14 pd_pool_id (of option to update)
-            OID_INT2,       // 15 code (of option to update)
-            OID_VARCHAR     // 16 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp6_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_INT8,       // 14 pd_pool_id
+            OID_INT8,       // 15 pd_pool_id (of option to update)
+            OID_INT2,       // 16 code (of option to update)
+            OID_VARCHAR     // 17 space (of option to update)
         },
         "UPDATE_OPTION6_PD_POOL_ID",
-        PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 6 AND o.pd_pool_id = $14 AND o.code = $15 AND o.space = $16)
+        PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 6 AND o.pd_pool_id = $15 AND o.code = $16 AND o.space = $17)
     },
 
     // Update existing shared network level option.
     {
         // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SHARED_NETWORK,
-        16,
+        17,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp6_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_INT8,       // 13 pd_pool_id
-            OID_VARCHAR,    // 14 shared_network_name (of option to update)
-            OID_INT2,       // 15 code (of option to update)
-            OID_VARCHAR     // 16 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp6_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_INT8,       // 14 pd_pool_id
+            OID_VARCHAR,    // 15 shared_network_name (of option to update)
+            OID_INT2,       // 16 code (of option to update)
+            OID_VARCHAR     // 17 space (of option to update)
         },
         "UPDATE_OPTION6_SHARED_NETWORK",
-        PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = $14 AND o.code = $15 AND o.space = $16)
+        PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = $15 AND o.code = $16 AND o.space = $17)
     },
 
     // Update existing client class level option.
     {
         // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_CLIENT_CLASS,
-        16,
+        17,
         {
             OID_INT2,       //  1 code
             OID_BYTEA,      //  2 value
             OID_TEXT,       //  3 formatted_value
             OID_VARCHAR,    //  4 space
             OID_BOOL,       //  5 persistent
-            OID_VARCHAR,    //  6 dhcp_client_class
-            OID_INT8,       //  7 dhcp6_subnet_id
-            OID_INT2,       //  8 scope_id
-            OID_TEXT,       //  9 user_context
-            OID_VARCHAR,    // 10 shared_network_name
-            OID_INT8,       // 11 pool_id
-            OID_TIMESTAMP,  // 12 modification_ts
-            OID_INT8,       // 13 pd_pool_id
-            OID_VARCHAR,    // 14 client_class (of option to update)
-            OID_INT2,       // 15 code (of option to update)
-            OID_VARCHAR     // 16 space (of option to update)
+            OID_BOOL,       //  6 cancelled
+            OID_VARCHAR,    //  7 dhcp_client_class
+            OID_INT8,       //  8 dhcp6_subnet_id
+            OID_INT2,       //  9 scope_id
+            OID_TEXT,       // 10 user_context
+            OID_VARCHAR,    // 11 shared_network_name
+            OID_INT8,       // 12 pool_id
+            OID_TIMESTAMP,  // 13 modification_ts
+            OID_INT8,       // 14 pd_pool_id
+            OID_VARCHAR,    // 15 client_class (of option to update)
+            OID_INT2,       // 16 code (of option to update)
+            OID_VARCHAR     // 17 space (of option to update)
         },
         "UPDATE_OPTION6_CLIENT_CLASS",
-        PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = $14 AND o.code = $15 AND o.space = $16)
+        PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = $15 AND o.code = $16 AND o.space = $17)
     },
 
     // Update existing client class with specifying its position.
index 4399cb08a2ec0703736967acfcee1a747df02315..93e51a5e8d5fd339bfa51db653fe3e660a44204b 100644 (file)
@@ -732,7 +732,7 @@ PgSqlConfigBackendImpl::getOptions(const int index,
             OptionDescriptorPtr desc = processOptionRow(universe, worker, 0);
             if (desc) {
                 // server_tag for the global option
-                ServerTag last_option_server_tag(worker.getString(12));
+                ServerTag last_option_server_tag(worker.getString(13));
                 desc->setServerTag(last_option_server_tag.get());
 
                 // If we're fetching options for a given server (explicit server
@@ -776,7 +776,8 @@ PgSqlConfigBackendImpl::getOptions(const int index,
 
 OptionDescriptorPtr
 PgSqlConfigBackendImpl::processOptionRow(const Option::Universe& universe,
-                                         PgSqlResultRowWorker& worker, size_t first_col) {
+                                         PgSqlResultRowWorker& worker,
+                                         size_t first_col) {
     // Some of the options have standard or custom definitions.
     // Depending whether the option has a definition or not a different
     // C++ class may be used to represent the option. Therefore, the
@@ -807,12 +808,21 @@ PgSqlConfigBackendImpl::processOptionRow(const Option::Universe& universe,
         persistent = worker.getBool(first_col + 5);
     }
 
+    // Check if the option is cancelled.
+    bool cancelled = false;
+    if (!worker.isColumnNull(first_col + 6)) {
+        cancelled = worker.getBool(first_col + 6);
+    }
+
     // Create option descriptor which encapsulates our option and adds
     // additional information, i.e. whether the option is persistent,
     // its option space and timestamp.
-    OptionDescriptorPtr desc = OptionDescriptor::create(option, persistent, formatted_value);
+    OptionDescriptorPtr desc = OptionDescriptor::create(option,
+                                                        persistent,
+                                                        cancelled,
+                                                        formatted_value);
     desc->space_name_ = space;
-    desc->setModificationTime(worker.getTimestamp(first_col + 11));
+    desc->setModificationTime(worker.getTimestamp(first_col + 12));
 
     // Set database id for the option.
     // @todo Can this actually ever be null and if it is, isn't that an error?
index 9c5532eb88f77f2d6be8a944a86eebb2e2cc1916..a1c9c693ec012d9ba9d70444ce2dbbc391ba39a0 100644 (file)
@@ -496,6 +496,7 @@ public:
     /// - formatted_value,
     /// - space,
     /// - persistent,
+    /// - cancelled,
     /// - dhcp4_subnet_id/dhcp6_subnet_id,
     /// - scope_id,
     /// - user_context,
index 375d914d96b5827ab3e1257e6f9076d957ddce21..8d459f197e1367468d12ce32f170428e8510ce2b 100644 (file)
@@ -77,6 +77,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp4_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -89,6 +90,7 @@ namespace {
     "  o.formatted_value," \
     "  o.space," \
     "  o.persistent," \
+    "  o.cancelled," \
     "  o.dhcp4_subnet_id," \
     "  o.scope_id," \
     "  o.user_context," \
@@ -183,6 +185,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp6_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -196,6 +199,7 @@ namespace {
     "  y.formatted_value," \
     "  y.space," \
     "  y.persistent," \
+    "  y.cancelled," \
     "  y.dhcp6_subnet_id," \
     "  y.scope_id," \
     "  y.user_context," \
@@ -209,6 +213,7 @@ namespace {
     "  o.formatted_value," \
     "  o.space," \
     "  o.persistent," \
+    "  o.cancelled," \
     "  o.dhcp6_subnet_id," \
     "  o.scope_id," \
     "  o.user_context," \
@@ -295,6 +300,7 @@ namespace {
       "  x.formatted_value," \
       "  x.space," \
       "  x.persistent," \
+      "  x.cancelled," \
       "  x.dhcp4_subnet_id," \
       "  x.scope_id," \
       "  x.user_context," \
@@ -335,6 +341,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp6_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -379,6 +386,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp6_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -425,6 +433,7 @@ namespace {
     "  o.formatted_value," \
     "  o.space," \
     "  o.persistent," \
+    "  o.cancelled," \
     "  o.dhcp4_subnet_id," \
     "  o.scope_id," \
     "  o.user_context," \
@@ -505,6 +514,7 @@ namespace {
     "  o.formatted_value," \
     "  o.space," \
     "  o.persistent," \
+    "  o.cancelled," \
     "  o.dhcp6_subnet_id," \
     "  o.scope_id," \
     "  o.user_context," \
@@ -594,6 +604,7 @@ namespace {
     "  o.formatted_value," \
     "  o.space," \
     "  o.persistent," \
+    "  o.cancelled," \
     "  o." #table_prefix "_subnet_id," \
     "  o.scope_id," \
     "  o.user_context," \
@@ -688,6 +699,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp4_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -751,6 +763,7 @@ namespace {
     "  x.formatted_value," \
     "  x.space," \
     "  x.persistent," \
+    "  x.cancelled," \
     "  x.dhcp6_subnet_id," \
     "  x.scope_id," \
     "  x.user_context," \
@@ -906,6 +919,7 @@ namespace {
     "  formatted_value," \
     "  space," \
     "  persistent," \
+    "  cancelled," \
     "  dhcp_client_class," \
     " " #table_prefix "_subnet_id," \
     "  scope_id," \
@@ -914,13 +928,13 @@ namespace {
     "  pool_id," \
     "  modification_ts" \
     pd_pool_id \
-    ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, cast($9 as json), $10, $11, $12" last ")"
+    ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, cast($10 as json), $11, $12, $13" last ")"
 
 #define PGSQL_INSERT_OPTION4() \
     PGSQL_INSERT_OPTION_COMMON(dhcp4, "", "")
 
 #define PGSQL_INSERT_OPTION6() \
-    PGSQL_INSERT_OPTION_COMMON(dhcp6, ", pd_pool_id ", ", $13")
+    PGSQL_INSERT_OPTION_COMMON(dhcp6, ", pd_pool_id ", ", $14")
 #endif
 
 #ifndef PGSQL_INSERT_OPTION_SERVER
@@ -1026,13 +1040,14 @@ namespace {
     "  formatted_value = $3," \
     "  space = $4," \
     "  persistent = $5," \
-    "  dhcp_client_class = $6," \
-    "  " #table_prefix "_subnet_id = $7," \
-    "  scope_id = $8," \
-    "  user_context = cast($9 as json)," \
-    "  shared_network_name = $10," \
-    "  pool_id = $11," \
-    "  modification_ts = $12 " \
+    "  cancelled = $6," \
+    "  dhcp_client_class = $7," \
+    "  " #table_prefix "_subnet_id = $8," \
+    "  scope_id = $9," \
+    "  user_context = cast($10 as json)," \
+    "  shared_network_name = $11," \
+    "  pool_id = $12," \
+    "  modification_ts = $13 " \
     pd_pool_id \
     "WHERE " #__VA_ARGS__
 
@@ -1040,7 +1055,7 @@ namespace {
     PGSQL_UPDATE_OPTION_NO_TAG(dhcp4, "", __VA_ARGS__)
 
 #define PGSQL_UPDATE_OPTION6_NO_TAG(...) \
-    PGSQL_UPDATE_OPTION_NO_TAG(dhcp6, ", pd_pool_id = $13 ", __VA_ARGS__)
+    PGSQL_UPDATE_OPTION_NO_TAG(dhcp6, ", pd_pool_id = $14 ", __VA_ARGS__)
 #endif
 
 #ifndef PGSQL_UPDATE_OPTION_WITH_TAG
@@ -1052,13 +1067,14 @@ namespace {
     "  formatted_value = $3," \
     "  space = $4," \
     "  persistent = $5," \
-    "  dhcp_client_class = $6," \
-    "  " #table_prefix "_subnet_id = $7," \
-    "  scope_id = $8," \
-    "  user_context = cast($9 as json)," \
-    "  shared_network_name = $10," \
-    "  pool_id = $11," \
-    "  modification_ts = $12 " \
+    "  cancelled = $6," \
+    "  dhcp_client_class = $7," \
+    "  " #table_prefix "_subnet_id = $8," \
+    "  scope_id = $9," \
+    "  user_context = cast($10 as json)," \
+    "  shared_network_name = $11," \
+    "  pool_id = $12," \
+    "  modification_ts = $13 " \
     pd_pool_id \
     "FROM " #table_prefix "_options_server as a, " \
     "     " #table_prefix "_server as s " \
@@ -1067,11 +1083,11 @@ namespace {
     #__VA_ARGS__
 
 #define PGSQL_UPDATE_OPTION4_WITH_TAG(...) \
-    PGSQL_UPDATE_OPTION_WITH_TAG(dhcp4, "", AND s.tag = $13 __VA_ARGS__)
+    PGSQL_UPDATE_OPTION_WITH_TAG(dhcp4, "", AND s.tag = $14 __VA_ARGS__)
 
 #define PGSQL_UPDATE_OPTION6_WITH_TAG(...) \
     PGSQL_UPDATE_OPTION_WITH_TAG(dhcp6, \
-    ", pd_pool_id = $13 ", AND s.tag = $14 __VA_ARGS__)
+    ", pd_pool_id = $14 ", AND s.tag = $15 __VA_ARGS__)
 #endif
 
 #ifndef PGSQL_UPDATE_CLIENT_CLASS4
index ba88e6f5f187a54e89ad26c5a2db792c6b5a12f8..a1d9e64589b5130b4534234e1785ea3f948873ca 100644 (file)
@@ -24,16 +24,17 @@ namespace isc {
 namespace dhcp {
 
 OptionDescriptorPtr
-OptionDescriptor::create(const OptionPtr& opt, bool persist,
+OptionDescriptor::create(const OptionPtr& opt, bool persist, bool cancel,
                          const std::string& formatted_value,
                          ConstElementPtr user_context) {
-    return (boost::make_shared<OptionDescriptor>(opt, persist, formatted_value,
+    return (boost::make_shared<OptionDescriptor>(opt, persist, cancel,
+                                                 formatted_value,
                                                  user_context));
 }
 
 OptionDescriptorPtr
-OptionDescriptor::create(bool persist) {
-    return (boost::make_shared<OptionDescriptor>(persist));
+OptionDescriptor::create(bool persist, bool cancel) {
+    return (boost::make_shared<OptionDescriptor>(persist, cancel));
 }
 
 OptionDescriptorPtr
@@ -44,6 +45,7 @@ OptionDescriptor::create(const OptionDescriptor& desc) {
 bool
 OptionDescriptor::equals(const OptionDescriptor& other) const {
     return ((persistent_ == other.persistent_) &&
+            (cancelled_ == other.cancelled_) &&
             (formatted_value_ == other.formatted_value_) &&
             (space_name_ == other.space_name_) &&
             option_->equals(other.option_));
@@ -64,10 +66,12 @@ CfgOption::equals(const CfgOption& other) const {
 }
 
 void
-CfgOption::add(const OptionPtr& option, const bool persistent,
+CfgOption::add(const OptionPtr& option,
+               const bool persistent,
+               const bool cancelled,
                const std::string& option_space,
                const uint64_t id) {
-    OptionDescriptor desc(option, persistent);
+    OptionDescriptor desc(option, persistent, cancelled);
     if (id > 0) {
         desc.setId(id);
     }
@@ -455,14 +459,17 @@ CfgOption::toElementWithMetadata(const bool include_metadata) const {
                 map->set("csv-format", Element::create(true));
                 map->set("data", Element::create(opt.formatted_value_));
             } else {
-                map->set("csv-format", Element::create(false));
                 std::vector<uint8_t> bin = opt.option_->toBinary();
-                std::string repr = util::encode::encodeHex(bin);
-                map->set("data", Element::create(repr));
+                if (!opt.cancelled_ || !bin.empty()) {
+                    map->set("csv-format", Element::create(false));
+                    std::string repr = util::encode::encodeHex(bin);
+                    map->set("data", Element::create(repr));
+                }
             }
             // Set the persistency flag
             map->set("always-send", Element::create(opt.persistent_));
-
+            // Set the cancelled flag.
+            map->set("never-send", Element::create(opt.cancelled_));
             // Include metadata if requested.
             if (include_metadata) {
                 map->set("metadata", opt.getMetadata());
@@ -504,13 +511,17 @@ CfgOption::toElementWithMetadata(const bool include_metadata) const {
                 map->set("csv-format", Element::create(true));
                 map->set("data", Element::create(opt.formatted_value_));
             } else {
-                map->set("csv-format", Element::create(false));
                 std::vector<uint8_t> bin = opt.option_->toBinary();
-                std::string repr = util::encode::encodeHex(bin);
-                map->set("data", Element::create(repr));
+                if (!opt.cancelled_ || !bin.empty()) {
+                    map->set("csv-format", Element::create(false));
+                    std::string repr = util::encode::encodeHex(bin);
+                    map->set("data", Element::create(repr));
+                }
             }
             // Set the persistency flag
             map->set("always-send", Element::create(opt.persistent_));
+            // Set the cancellation flag
+            map->set("never-send", Element::create(opt.cancelled_));
             // Push on the list
             result->add(map);
         }
index d2631d6f76406a78c405890d66fd6392dd9760c9..58aca4dce51fd06b0ef19d06d0a99d2f405b06a3 100644 (file)
@@ -42,7 +42,7 @@ typedef std::vector<OptionDescriptor> OptionDescriptorList;
 /// Option descriptor holds instance of an option and additional information
 /// for this option. This information comprises whether this option is sent
 /// to DHCP client only on request (persistent = false) or always
-/// (persistent = true).
+/// (persistent = true), or must never send (cancelled = true).
 class OptionDescriptor : public data::StampedElement, public data::UserContext {
 public:
     /// @brief Option instance.
@@ -54,6 +54,14 @@ public:
     /// sent to the client when requested using ORO or PRL option.
     bool persistent_;
 
+    /// @brief Cancelled flag.
+    ///
+    /// If true, option is never sent to the client. If false, option is
+    /// sent when it should.
+    /// @note: When true the action of this flag is final i.e. it can't be
+    /// overridden at a more specific level and has precedence over persist.
+    bool cancelled_;
+
     /// @brief Option value in textual (CSV) format.
     ///
     /// This field is used to convey option value in human readable format,
@@ -84,13 +92,14 @@ public:
     ///
     /// @param opt option instance.
     /// @param persist if true, option is always sent.
+    /// @param cancel if true, option is never sent.
     /// @param formatted_value option value in the textual format (optional).
     /// @param user_context user context (optional).
-    OptionDescriptor(const OptionPtr& opt, bool persist,
+    OptionDescriptor(const OptionPtr& opt, bool persist, bool cancel,
                      const std::string& formatted_value = "",
                      data::ConstElementPtr user_context = data::ConstElementPtr())
         : data::StampedElement(), option_(opt), persistent_(persist),
-          formatted_value_(formatted_value),
+          cancelled_(cancel), formatted_value_(formatted_value),
           space_name_() {
         setContext(user_context);
     };
@@ -98,9 +107,10 @@ public:
     /// @brief Constructor.
     ///
     /// @param persist if true option is always sent.
-    OptionDescriptor(bool persist)
+    /// @param cancel if true, option is never sent.
+    OptionDescriptor(bool persist, bool cancel)
         : data::StampedElement(), option_(OptionPtr()), persistent_(persist),
-          formatted_value_(), space_name_() {};
+          cancelled_(cancel), formatted_value_(), space_name_() {};
 
     /// @brief Copy constructor.
     ///
@@ -109,6 +119,7 @@ public:
         : data::StampedElement(desc),
           option_(desc.option_),
           persistent_(desc.persistent_),
+          cancelled_(desc.cancelled_),
           formatted_value_(desc.formatted_value_),
           space_name_(desc.space_name_) {
         setContext(desc.getContext());
@@ -123,6 +134,7 @@ public:
             data::StampedElement::operator=(other);
             option_ = other.option_;
             persistent_ = other.persistent_;
+            cancelled_ = other.cancelled_;
             formatted_value_ = other.formatted_value_;
             space_name_ = other.space_name_;
             setContext(other.getContext());
@@ -134,12 +146,14 @@ public:
     ///
     /// @param opt option instance.
     /// @param persist if true, option is always sent.
+    /// @param cancel if true, option is never sent.
     /// @param formatted_value option value in the textual format (optional).
     /// @param user_context user context (optional).
     ///
     /// @return Pointer to the @c OptionDescriptor instance.
     static OptionDescriptorPtr create(const OptionPtr& opt,
                                       bool persist,
+                                      bool cancel,
                                       const std::string& formatted_value = "",
                                       data::ConstElementPtr user_context =
                                       data::ConstElementPtr());
@@ -147,9 +161,10 @@ public:
     /// @brief Factory function creating an instance of the @c OptionDescriptor.
     ///
     /// @param persist if true option is always sent.
+    /// @param cancel if true, option is never sent.
     ///
     /// @return Pointer to the @c OptionDescriptor instance.
-    static OptionDescriptorPtr create(bool persist);
+    static OptionDescriptorPtr create(bool persist, bool cancel);
 
     /// @brief Factory function creating an instance of the @c OptionDescriptor.
     ///
@@ -195,12 +210,14 @@ public:
 /// - persistency flag index: used to search option descriptors with
 /// 'persistent' flag set to true.
 ///
-/// This container is the equivalent of three separate STL containers:
+/// This container is the equivalent of four separate STL containers:
 /// - std::list of all options,
 /// - std::multimap of options with option code used as a multimap key,
 /// - std::multimap of option descriptors with option persistency flag
 /// used as a multimap key.
-/// The major advantage of this container over 3 separate STL containers
+/// - std::multimap of option descriptors with option cancellation flag
+/// used as a multimap key.
+/// The major advantage of this container over 4 separate STL containers
 /// is automatic synchronization of all indexes when elements are added,
 /// removed or modified in the container. With separate containers,
 /// the synchronization would have to be guaranteed by the Subnet class
@@ -268,6 +285,15 @@ typedef boost::multi_index_container<
             boost::multi_index::tag<OptionIdIndexTag>,
             boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t,
                                               &data::BaseStampedElement::getId>
+        >,
+        // Start definition of index #5.
+        // Use 'cancelled' struct member as a key.
+        boost::multi_index::hashed_non_unique<
+            boost::multi_index::member<
+                OptionDescriptor,
+                bool,
+                &OptionDescriptor::cancelled_
+            >
         >
     >
 > OptionContainer;
@@ -288,6 +314,13 @@ typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
 /// the beginning of the range, the second element represents the end.
 typedef std::pair<OptionContainerPersistIndex::const_iterator,
                   OptionContainerPersistIndex::const_iterator> OptionContainerPersistRange;
+/// Type of the index #5 - option cancellation flag.
+typedef OptionContainer::nth_index<5>::type OptionContainerCancelIndex;
+/// Pair of iterators to represent the range of options having the
+/// same cancellation flag. The first element in this pair represents
+/// the beginning of the range, the second element represents the end.
+typedef std::pair<OptionContainerCancelIndex::const_iterator,
+                  OptionContainerCancelIndex::const_iterator> OptionContainerCancelRange;
 
 /// @brief Represents option data configuration for the DHCP server.
 ///
@@ -375,12 +408,14 @@ public:
     /// @param option Pointer to the option being added.
     /// @param persistent Boolean value which specifies if the option should
     /// be sent to the client regardless if requested (true), or nor (false)
+    /// @param cancelled Boolean value which specifies if the option must
+    /// never be sent to the client.
     /// @param option_space Option space name.
     /// @param id Optional database id to be associated with the option.
     ///
     /// @throw isc::BadValue if the option space is invalid.
     void add(const OptionPtr& option, const bool persistent,
-             const std::string& option_space,
+             const bool cancelled, const std::string& option_space,
              const uint64_t id = 0);
 
     /// @brief A variant of the @ref CfgOption::add method which takes option
@@ -552,14 +587,14 @@ public:
         // Check for presence of options.
         OptionContainerPtr options = getAll(key);
         if (!options || options->empty()) {
-            return (OptionDescriptor(false));
+            return (OptionDescriptor(false, false));
         }
 
         // Some options present, locate the one we are interested in.
         const OptionContainerTypeIndex& idx = options->get<1>();
         OptionContainerTypeIndex::const_iterator od_itr = idx.find(option_code);
         if (od_itr == idx.end()) {
-            return (OptionDescriptor(false));
+            return (OptionDescriptor(false, false));
         }
 
         return (*od_itr);
index af1ffc9400a580af9fb1efb7421c2bf8af5d48a4..6af6dd28332e724b1bb7c652d075bf40b9aac2bb 100644 (file)
@@ -837,7 +837,7 @@ class MySqlHostWithOptionsExchange : public MySqlHostExchange {
 private:
 
     /// @brief Number of columns holding DHCPv4 or DHCPv6 option information.
-    static const size_t OPTION_COLUMNS = 7;
+    static const size_t OPTION_COLUMNS = 8;
 
     /// @brief Receives DHCPv4 or DHCPv6 options information from the
     /// dhcp4_options or dhcp6_options tables respectively.
@@ -866,7 +866,8 @@ private:
                         const size_t start_column)
         : universe_(universe), start_column_(start_column), option_id_(0),
           code_(0), value_length_(0), formatted_value_length_(0),
-          space_length_(0), persistent_(false), user_context_length_(0),
+          space_length_(0), persistent_(false), cancelled_(false),
+          user_context_length_(0),
           option_id_null_(MLM_FALSE), code_null_(MLM_FALSE),
           value_null_(MLM_FALSE), formatted_value_null_(MLM_FALSE),
           space_null_(MLM_FALSE), user_context_null_(MLM_FALSE),
@@ -875,7 +876,8 @@ private:
           formatted_value_index_(start_column_ + 3),
           space_index_(start_column_ + 4),
           persistent_index_(start_column_ + 5),
-          user_context_index_(start_column_ + 6),
+          cancelled_index_(start_column_ + 6),
+          user_context_index_(start_column_ + 7),
           most_recent_option_id_(0) {
 
             memset(value_, 0, sizeof(value_));
@@ -998,7 +1000,8 @@ private:
                 }
             }
 
-            OptionDescriptor desc(option, persistent_, formatted_value);
+            OptionDescriptor desc(option, persistent_, cancelled_,
+                                  formatted_value);
 
             // Set the user context if there is one into the option descriptor.
             if (!user_context.empty()) {
@@ -1029,6 +1032,7 @@ private:
             columns[formatted_value_index_] = "formatted_value";
             columns[space_index_] = "space";
             columns[persistent_index_] = "persistent";
+            columns[cancelled_index_] = "cancelled";
             columns[user_context_index_] = "user_context";
         }
 
@@ -1047,6 +1051,7 @@ private:
             option_id_ = 0;
             code_ = 0;
             persistent_ = false;
+            cancelled_ = false;
             option_id_null_ = MLM_FALSE;
             code_null_ = MLM_FALSE;
             value_null_ = MLM_FALSE;
@@ -1100,6 +1105,11 @@ private:
             bind[persistent_index_].buffer = reinterpret_cast<char*>(&persistent_);
             bind[persistent_index_].is_unsigned = MLM_TRUE;
 
+            // cancelled : TINYINT(1) NOT NULL DEFAULT 0
+            bind[cancelled_index_].buffer_type = MYSQL_TYPE_TINY;
+            bind[cancelled_index_].buffer = reinterpret_cast<char*>(&cancelled_);
+            bind[cancelled_index_].is_unsigned = MLM_TRUE;
+
             // user_context : TEXT NULL
             user_context_length_ = sizeof(user_context_);
             bind[user_context_index_].buffer_type = MYSQL_TYPE_STRING;
@@ -1145,6 +1155,9 @@ private:
         /// requested.
         bool persistent_;
 
+        /// @brief Flag indicating if option must be never sent.
+        bool cancelled_;
+
         /// @brief Buffer holding textual user context of an option.
         char user_context_[USER_CONTEXT_MAX_LEN];
 
@@ -1193,6 +1206,9 @@ private:
 
         /// @brief Persistent
         size_t persistent_index_;
+
+        /// @brief Cancelled
+        size_t cancelled_index_;
         //@}
 
         /// @brief User context
@@ -1746,18 +1762,18 @@ class MySqlOptionExchange {
 private:
 
     /// @brief Number of columns in the tables holding options.
-    static const size_t OPTION_COLUMNS = 10;
+    static const size_t OPTION_COLUMNS = 11;
 
 public:
 
     /// @brief Constructor.
     MySqlOptionExchange()
         : type_(0), value_len_(0), formatted_value_len_(0), space_(),
-          space_len_(0), persistent_(false), user_context_(),
-          user_context_len_(0), subnet_id_(SUBNET_ID_UNUSED),
+          space_len_(0), persistent_(false), cancelled_(false),
+          user_context_(), user_context_len_(0), subnet_id_(SUBNET_ID_UNUSED),
           host_id_(0), option_() {
 
-        BOOST_STATIC_ASSERT(9 < OPTION_COLUMNS);
+        BOOST_STATIC_ASSERT(10 < OPTION_COLUMNS);
     }
 
     /// @brief Creates binding array to insert option data into database.
@@ -1836,35 +1852,41 @@ public:
             bind_[5].buffer = reinterpret_cast<char*>(&persistent_);
             bind_[5].is_unsigned = MLM_TRUE;
 
+            // cancelled: TINYINT(1) NOT NULL DEFAULT 0
+            cancelled_ = opt_desc.cancelled_;
+            bind_[6].buffer_type = MYSQL_TYPE_TINY;
+            bind_[6].buffer = reinterpret_cast<char*>(&cancelled_);
+            bind_[6].is_unsigned = MLM_TRUE;
+
             // user_context: TEST NULL,
             ConstElementPtr ctx = opt_desc.getContext();
             if (ctx) {
                 user_context_ = ctx->str();
                 user_context_len_ = user_context_.size();
-                bind_[6].buffer_type = MYSQL_TYPE_STRING;
-                bind_[6].buffer = const_cast<char*>(user_context_.c_str());
-                bind_[6].buffer_length = user_context_len_;
-                bind_[6].length = &user_context_len_;
+                bind_[7].buffer_type = MYSQL_TYPE_STRING;
+                bind_[7].buffer = const_cast<char*>(user_context_.c_str());
+                bind_[7].buffer_length = user_context_len_;
+                bind_[7].length = &user_context_len_;
             } else {
-                bind_[6].buffer_type = MYSQL_TYPE_NULL;
+                bind_[7].buffer_type = MYSQL_TYPE_NULL;
             }
 
             // dhcp4_subnet_id: INT UNSIGNED NULL
             if (!subnet_id.unspecified()) {
                 subnet_id_ = subnet_id;
-                bind_[7].buffer_type = MYSQL_TYPE_LONG;
-                bind_[7].buffer = reinterpret_cast<char*>(subnet_id_);
-                bind_[7].is_unsigned = MLM_TRUE;
+                bind_[8].buffer_type = MYSQL_TYPE_LONG;
+                bind_[8].buffer = reinterpret_cast<char*>(subnet_id_);
+                bind_[8].is_unsigned = MLM_TRUE;
 
             } else {
-                bind_[7].buffer_type = MYSQL_TYPE_NULL;
+                bind_[8].buffer_type = MYSQL_TYPE_NULL;
             }
 
             // host_id: INT UNSIGNED NOT NULL
             host_id_ = host_id;
-            bind_[8].buffer_type = MYSQL_TYPE_LONG;
-            bind_[8].buffer = reinterpret_cast<char*>(&host_id_);
-            bind_[8].is_unsigned = MLM_TRUE;
+            bind_[9].buffer_type = MYSQL_TYPE_LONG;
+            bind_[9].buffer = reinterpret_cast<char*>(&host_id_);
+            bind_[9].is_unsigned = MLM_TRUE;
 
         } catch (const std::exception& ex) {
             isc_throw(DbOperationError,
@@ -1900,6 +1922,10 @@ private:
     /// a client or only when requested.
     bool persistent_;
 
+    /// @brief Boolean flag indicating if the option must be never returned
+    /// to a client.
+    bool cancelled_;
+
     /// @brief User context.
     std::string user_context_;
 
@@ -2281,9 +2307,9 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
-                "o4.persistent, o4.user_context, "
+                "o4.persistent, o4.cancelled, o4.user_context, "
                 "o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
-                "o6.persistent, o6.user_context, "
+                "o6.persistent, o6.cancelled, o6.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
                 "r.dhcp6_iaid "
             "FROM hosts AS h "
@@ -2306,7 +2332,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context "
+                "o.persistent, o.cancelled, o.user_context "
             "FROM hosts AS h "
             "LEFT JOIN dhcp4_options AS o "
                 "ON h.host_id = o.host_id "
@@ -2323,7 +2349,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context "
+                "o.persistent, o.cancelled, o.user_context "
             "FROM hosts AS h "
             "LEFT JOIN dhcp4_options AS o "
                 "ON h.host_id = o.host_id "
@@ -2342,7 +2368,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context, "
+                "o.persistent, o.cancelled, o.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
                 "r.dhcp6_iaid "
             "FROM hosts AS h "
@@ -2365,7 +2391,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context "
+                "o.persistent, o.cancelled, o.user_context "
             "FROM hosts AS h "
             "LEFT JOIN dhcp4_options AS o "
                 "ON h.host_id = o.host_id "
@@ -2386,7 +2412,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context,"
+                "o.persistent, o.cancelled, o.user_context,"
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
                 "r.dhcp6_iaid "
             "FROM hosts AS h "
@@ -2413,7 +2439,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context, "
+                "o.persistent, o.cancelled, o.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
                 "r.dhcp6_iaid "
             "FROM hosts AS h "
@@ -2434,7 +2460,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context "
+                "o.persistent, o.cancelled, o.user_context "
             "FROM hosts AS h "
             "LEFT JOIN dhcp4_options AS o "
                 "ON h.host_id = o.host_id "
@@ -2453,7 +2479,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context, "
+                "o.persistent, o.cancelled, o.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
                 "r.dhcp6_iaid "
             "FROM hosts AS h "
@@ -2476,9 +2502,9 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
-                "o4.persistent, o4.user_context, "
+                "o4.persistent, o4.cancelled, o4.user_context, "
                 "o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
-                "o6.persistent, o6.user_context, "
+                "o6.persistent, o6.cancelled, o6.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
                 "r.dhcp6_iaid "
             "FROM hosts AS h "
@@ -2501,7 +2527,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context "
+                "o.persistent, o.cancelled, o.user_context "
             "FROM hosts AS h "
             "LEFT JOIN dhcp4_options AS o "
                 "ON h.host_id = o.host_id "
@@ -2519,7 +2545,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context, "
+                "o.persistent, o.cancelled, o.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
                 "r.dhcp6_iaid "
             "FROM hosts AS h "
@@ -2542,7 +2568,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context "
+                "o.persistent, o.cancelled, o.user_context "
             "FROM ( SELECT * FROM hosts AS h "
                     "WHERE h.dhcp4_subnet_id = ? AND h.host_id > ? "
                     "ORDER BY h.host_id "
@@ -2564,7 +2590,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context, "
+                "o.persistent, o.cancelled, o.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
                 "r.dhcp6_iaid "
             "FROM ( SELECT * FROM hosts AS h "
@@ -2589,7 +2615,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context "
+                "o.persistent, o.cancelled, o.user_context "
             "FROM ( SELECT * FROM hosts AS h "
                     "WHERE h.host_id > ? "
                     "ORDER BY h.host_id "
@@ -2611,7 +2637,7 @@ TaggedStatementArray tagged_statements = { {
                 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
                 "h.dhcp4_boot_file_name, h.auth_key, "
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
-                "o.persistent, o.user_context, "
+                "o.persistent, o.cancelled, o.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
                 "r.dhcp6_iaid "
             "FROM ( SELECT * FROM hosts AS h "
@@ -2681,15 +2707,15 @@ TaggedStatementArray tagged_statements = { {
     // Using fixed scope_id = 3, which associates an option with host.
     {MySqlHostDataSourceImpl::INSERT_V4_HOST_OPTION,
             "INSERT INTO dhcp4_options(option_id, code, value, formatted_value, space, "
-                "persistent, user_context, dhcp4_subnet_id, host_id, scope_id) "
-            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"},
+                "persistent, cancelled, user_context, dhcp4_subnet_id, host_id, scope_id) "
+            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"},
 
     // Inserts a single DHCPv6 option into 'dhcp6_options' table.
     // Using fixed scope_id = 3, which associates an option with host.
     {MySqlHostDataSourceImpl::INSERT_V6_HOST_OPTION,
             "INSERT INTO dhcp6_options(option_id, code, value, formatted_value, space, "
-                "persistent, user_context, dhcp6_subnet_id, host_id, scope_id) "
-            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"},
+                "persistent, cancelled, user_context, dhcp6_subnet_id, host_id, scope_id) "
+            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"},
 
     // Delete IPv4 reservations by subnet id and reserved address.
     {MySqlHostDataSourceImpl::DEL_HOST_ADDR4,
index e26e1c5e0b14931526222dc19a267a67a6addfc6..6c09f8a8df17dd025e59fa905e1a324a4d6f6e4e 100644 (file)
@@ -110,7 +110,7 @@ OptionDataParser::extractName(ConstElementPtr parent) const {
     return (Optional<std::string>(name));
 }
 
-std::string
+Optional<std::string>
 OptionDataParser::extractData(ConstElementPtr parent) const {
     std::string data;
     try {
@@ -118,10 +118,10 @@ OptionDataParser::extractData(ConstElementPtr parent) const {
 
     } catch (...) {
         // The "data" parameter was not found. Return an empty value.
-        return (data);
+        return (Optional<std::string>());
     }
 
-    return (data);
+    return (Optional<std::string>(data));
 }
 
 Optional<bool>
@@ -186,6 +186,19 @@ OptionDataParser::extractPersistent(ConstElementPtr parent) const {
     return (Optional<bool>(persist));
 }
 
+Optional<bool>
+OptionDataParser::extractCancelled(ConstElementPtr parent) const {
+    bool cancel = false;
+    try {
+        cancel = getBoolean(parent, "never-send");
+
+    } catch (...) {
+        return (Optional<bool>());
+    }
+
+    return (Optional<bool>(cancel));
+}
+
 OptionDefinitionPtr
 OptionDataParser::findOptionDefinition(const std::string& option_space,
                                        const Optional<uint32_t>& option_code,
@@ -262,7 +275,8 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
     Optional<std::string> name_param = extractName(option_data);
     Optional<bool> csv_format_param = extractCSVFormat(option_data);
     Optional<bool> persist_param = extractPersistent(option_data);
-    std::string data_param = extractData(option_data);
+    Optional<bool> cancel_param = extractCancelled(option_data);
+    Optional<std::string> data_param = extractData(option_data);
     std::string space_param = extractSpace(option_data);
     ConstElementPtr user_context = option_data->get("user-context");
 
@@ -299,6 +313,31 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
                       << getPosition("name", option_data)
                       << ")");
         }
+    } else {
+        // Option name is specified it should match the name in the definition.
+        if (!name_param.unspecified() && (def->getName() != name_param.get())) {
+            isc_throw(DhcpConfigError, "specified option name '"
+                      << name_param << "' does not match the "
+                      << "option definition: '" << space_param
+                      << "." << def->getName() << "' ("
+                      << getPosition("name", option_data)
+                      << ")");
+        }
+    }
+
+    // No data and cancelled is a supported special case.
+    if (!cancel_param.unspecified() && cancel_param &&
+        data_param.unspecified()) {
+        uint16_t code;
+        if (def) {
+            code = def->getCode();
+        } else {
+            code = static_cast<uint16_t>(code_param);
+        }
+        OptionPtr option(new Option(universe, code));
+        bool persistent = !persist_param.unspecified() && persist_param;
+        OptionDescriptor desc(option, persistent, true, "", user_context);
+        return (make_pair(desc, space_param));
     }
 
     // Transform string of hexadecimal digits into binary format.
@@ -336,7 +375,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
         }
     }
 
-    OptionDescriptor desc(false);
+    OptionDescriptor desc(false, false);
 
     if (!def) {
         // @todo We have a limited set of option definitions initialized at
@@ -349,18 +388,8 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
 
         desc.option_ = option;
         desc.persistent_ = !persist_param.unspecified() && persist_param;
+        desc.cancelled_ = !cancel_param.unspecified() && cancel_param;
     } else {
-
-        // Option name is specified it should match the name in the definition.
-        if (!name_param.unspecified() && (def->getName() != name_param.get())) {
-            isc_throw(DhcpConfigError, "specified option name '"
-                      << name_param << "' does not match the "
-                      << "option definition: '" << space_param
-                      << "." << def->getName() << "' ("
-                      << getPosition("name", option_data)
-                      << ")");
-        }
-
         // Option definition has been found so let's use it to create
         // an instance of our option.
         try {
@@ -370,6 +399,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
                 def->optionFactory(universe, def->getCode(), binary);
             desc.option_ = option;
             desc.persistent_ = !persist_param.unspecified() && persist_param;
+            desc.cancelled_ = !cancel_param.unspecified() && cancel_param;
             if (use_csv) {
                 desc.formatted_value_ = data_param;
             }
@@ -412,7 +442,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
     }
 
     // All went good, so we can set the option space name.
-    return make_pair(desc, space_param);
+    return (make_pair(desc, space_param));
 }
 
 // **************************** OptionDataListParser *************************
index a21cdf2c453928c467c219df730790da3d448562..e8b47f2141c91607ebde70a35f87ba1b78128843 100644 (file)
@@ -151,7 +151,8 @@ protected:
     /// @param parent A data element holding full option data configuration.
     /// @return Option data as a string. It will return empty string if
     /// option data is unspecified.
-    std::string extractData(data::ConstElementPtr parent) const;
+    util::Optional<std::string>
+    extractData(data::ConstElementPtr parent) const;
 
     /// @brief Retrieves option space name.
     ///
@@ -169,6 +170,11 @@ protected:
     /// @return Value of the persistent parameter, possibly unspecified.
     util::Optional<bool> extractPersistent(data::ConstElementPtr parent) const;
 
+    /// @brief Retrieves cancelled/never-send parameter as an optional value.
+    ///
+    /// @return Value of the cancelled parameter, possibly unspecified.
+    util::Optional<bool> extractCancelled(data::ConstElementPtr parent) const;
+
     /// @brief Address family: @c AF_INET or @c AF_INET6.
     uint16_t address_family_;
 
index 2475fc49a6e59771e7385f64cd404b2909cedbd5..551b00154999d6c695e5cb6e054bed03feb7be42 100644 (file)
@@ -185,6 +185,7 @@ const SimpleKeywords SimpleParser4::OPTION4_PARAMETERS = {
     { "space",        Element::string },
     { "csv-format",   Element::boolean },
     { "always-send",  Element::boolean },
+    { "never-send",   Element::boolean },
     { "user-context", Element::map },
     { "comment",      Element::string },
     { "metadata",     Element::map }
@@ -198,7 +199,8 @@ const SimpleKeywords SimpleParser4::OPTION4_PARAMETERS = {
 const SimpleDefaults SimpleParser4::OPTION4_DEFAULTS = {
     { "space",        Element::string,  "dhcp4"}, // DHCP4_OPTION_SPACE
     { "csv-format",   Element::boolean, "true"},
-    { "always-send",  Element::boolean, "false"}
+    { "always-send",  Element::boolean, "false"},
+    { "never-send",   Element::boolean, "false"}
 };
 
 /// @brief This table defines all subnet parameters for DHCPv4.
index eae89340c7d699f2f974665dfd79931236e2cd32..be310a30256ba5c2b07b521f95c584738e54a008 100644 (file)
@@ -183,6 +183,7 @@ const SimpleKeywords SimpleParser6::OPTION6_PARAMETERS = {
     { "space",        Element::string },
     { "csv-format",   Element::boolean },
     { "always-send",  Element::boolean },
+    { "never-send",   Element::boolean },
     { "user-context", Element::map },
     { "comment",      Element::string },
     { "metadata",     Element::map }
@@ -196,7 +197,8 @@ const SimpleKeywords SimpleParser6::OPTION6_PARAMETERS = {
 const SimpleDefaults SimpleParser6::OPTION6_DEFAULTS = {
     { "space",        Element::string,  "dhcp6"}, // DHCP6_OPTION_SPACE
     { "csv-format",   Element::boolean, "true"},
-    { "always-send",  Element::boolean, "false"}
+    { "always-send",  Element::boolean, "false"},
+    { "never-send",   Element::boolean, "false"}
 };
 
 /// @brief This table defines all subnet parameters for DHCPv6.
index a1251be692ad39676182618cb7adebdcc865b250..ed4de155540a608f0c93fc4e042cd62abc351c05 100644 (file)
@@ -474,7 +474,7 @@ class PgSqlHostWithOptionsExchange : public PgSqlHostExchange {
 private:
 
     /// @brief Number of columns holding DHCPv4 or DHCPv6 option information.
-    static const size_t OPTION_COLUMNS = 7;
+    static const size_t OPTION_COLUMNS = 8;
 
     /// @brief Receives DHCPv4 or DHCPv6 options information from the
     /// dhcp4_options or dhcp6_options tables respectively.
@@ -507,7 +507,8 @@ private:
           formatted_value_index_(start_column_ + 3),
           space_index_(start_column_ + 4),
           persistent_index_(start_column_ + 5),
-          user_context_index_(start_column_ + 6),
+          cancelled_index_(start_column_ + 6),
+          user_context_index_(start_column_ + 7),
           most_recent_option_id_(0) {
         }
 
@@ -610,6 +611,11 @@ private:
             PgSqlExchange::getColumnValue(r, row, persistent_index_,
                                           persistent);
 
+            // cancelled: BOOL default false
+            bool cancelled;
+            PgSqlExchange::getColumnValue(r, row, cancelled_index_,
+                                          cancelled);
+
             // user_context: TEXT
             std::string user_context;
             if (!isColumnNull(r, row, user_context_index_)) {
@@ -671,7 +677,8 @@ private:
                 }
             }
 
-            OptionDescriptor desc(option, persistent, formatted_value);
+            OptionDescriptor desc(option, persistent, cancelled,
+                                  formatted_value);
 
             // Set the user context if there is one into the option descriptor.
             if (!user_context.empty()) {
@@ -702,6 +709,7 @@ private:
             columns[formatted_value_index_] = "formatted_value";
             columns[space_index_] = "space";
             columns[persistent_index_] = "persistent";
+            columns[cancelled_index_] = "cancelled";
             columns[user_context_index_] = "user_context";
         }
 
@@ -733,6 +741,9 @@ private:
 
         /// @brief Persistent
         size_t persistent_index_;
+
+        /// @brief Cancelled
+        size_t cancelled_index_;
         //@}
 
         /// @brief User context
@@ -1163,14 +1174,15 @@ private:
     static const int FORMATTED_VALUE_COL = 3;
     static const int SPACE_COL = 4;
     static const int PERSISTENT_COL = 5;
-    static const int USER_CONTEXT_COL = 6;
-    static const int DHCP_CLIENT_CLASS_COL = 7;
-    static const int DHCP_SUBNET_ID_COL = 8;
-    static const int HOST_ID_COL = 9;
-    static const int SCOPE_ID_COL = 10;
+    static const int CANCELLED_COL = 6;
+    static const int USER_CONTEXT_COL = 7;
+    static const int DHCP_CLIENT_CLASS_COL = 8;
+    static const int DHCP_SUBNET_ID_COL = 9;
+    static const int HOST_ID_COL = 10;
+    static const int SCOPE_ID_COL = 11;
 
     /// @brief Number of columns in the tables holding options.
-    static const size_t OPTION_COLUMNS = 11;
+    static const size_t OPTION_COLUMNS = 12;
 
 public:
 
@@ -1184,13 +1196,14 @@ public:
         columns_[FORMATTED_VALUE_COL] = "formatted_value";
         columns_[SPACE_COL] = "space";
         columns_[PERSISTENT_COL] = "persistent";
+        columns_[CANCELLED_COL] = "cancelled";
         columns_[USER_CONTEXT_COL] = "user_context";
         columns_[DHCP_CLIENT_CLASS_COL] = "dhcp_client_class";
         columns_[DHCP_SUBNET_ID_COL] = "dhcp_subnet_id";
         columns_[HOST_ID_COL] = "host_id";
         columns_[SCOPE_ID_COL] = "scope_id";
 
-        BOOST_STATIC_ASSERT(10 < OPTION_COLUMNS);
+        BOOST_STATIC_ASSERT(11 < OPTION_COLUMNS);
     }
 
     /// @brief Creates binding array to insert option data into database.
@@ -1253,6 +1266,9 @@ public:
             // persistent: BOOLEAN DEFAULT false
             bind_array->add(opt_desc.persistent_);
 
+            // cancelled: BOOLEAN DEFAULT false
+            bind_array->add(opt_desc.cancelled_);
+
             // user_context: TEXT NULL,
             ConstElementPtr ctx = opt_desc.getContext();
             if (ctx) {
@@ -1645,9 +1661,9 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
-     "  o4.persistent, o4.user_context, "
+     "  o4.persistent, o4.cancelled, o4.user_context, "
      "  o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
-     "  o6.persistent, o6.user_context, "
+     "  o6.persistent, o6.cancelled, o6.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
      "FROM hosts AS h "
      "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id "
@@ -1670,7 +1686,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context "
+     "  o.persistent, o.cancelled, o.user_context "
      "FROM hosts AS h "
      "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
      "WHERE ipv4_address = $1 "
@@ -1690,7 +1706,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context "
+     "  o.persistent, o.cancelled, o.user_context "
      "FROM hosts AS h "
      "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
      "WHERE h.dhcp4_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
@@ -1712,7 +1728,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context, "
+     "  o.persistent, o.cancelled, o.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
      "FROM hosts AS h "
      "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
@@ -1736,7 +1752,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context "
+     "  o.persistent, o.cancelled, o.user_context "
      "FROM hosts AS h "
      "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
      "WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 "
@@ -1760,7 +1776,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context, "
+     "  o.persistent, o.cancelled, o.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, "
      "  r.dhcp6_iaid "
      "FROM hosts AS h "
@@ -1789,7 +1805,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context, "
+     "  o.persistent, o.cancelled, o.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, "
      "  r.dhcp6_iaid "
      "FROM hosts AS h "
@@ -1814,7 +1830,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context "
+     "  o.persistent, o.cancelled, o.user_context "
      "FROM hosts AS h "
      "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
      "WHERE h.dhcp4_subnet_id = $1 "
@@ -1841,7 +1857,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context, "
+     "  o.persistent, o.cancelled, o.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
      "FROM hosts AS h "
      "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
@@ -1866,9 +1882,9 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
-     "  o4.persistent, o4.user_context, "
+     "  o4.persistent, o4.cancelled, o4.user_context, "
      "  o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
-     "  o6.persistent, o6.user_context, "
+     "  o6.persistent, o6.cancelled, o6.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
      "FROM hosts AS h "
      "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id "
@@ -1892,7 +1908,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context "
+     "  o.persistent, o.cancelled, o.user_context "
      "FROM hosts AS h "
      "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
      "WHERE lower(h.hostname) = $1 AND h.dhcp4_subnet_id = $2 "
@@ -1916,7 +1932,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context, "
+     "  o.persistent, o.cancelled, o.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
      "FROM hosts AS h "
      "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
@@ -1939,7 +1955,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context "
+     "  o.persistent, o.cancelled, o.user_context "
      "FROM ( SELECT * FROM hosts AS h "
      "       WHERE h.dhcp4_subnet_id = $1 AND h.host_id > $2 "
      "       ORDER BY h.host_id "
@@ -1965,7 +1981,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context, "
+     "  o.persistent, o.cancelled, o.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
      "FROM ( SELECT * FROM hosts AS h "
      "       WHERE h.dhcp6_subnet_id = $1 AND h.host_id > $2 "
@@ -1990,7 +2006,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context "
+     "  o.persistent, o.cancelled, o.user_context "
      "FROM ( SELECT * FROM hosts AS h "
      "       WHERE h.host_id > $1 "
      "       ORDER BY h.host_id "
@@ -2016,7 +2032,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
      "  h.dhcp4_boot_file_name, h.auth_key, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
-     "  o.persistent, o.user_context, "
+     "  o.persistent, o.cancelled, o.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
      "FROM ( SELECT * FROM hosts AS h "
      "       WHERE h.host_id > $1 "
@@ -2104,25 +2120,25 @@ TaggedStatementArray tagged_statements = { {
     // PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION
     // Inserts a single DHCPv4 option into 'dhcp4_options' table.
     // Using fixed scope_id = 3, which associates an option with host.
-    {7,
+    {8,
      { OID_INT2, OID_BYTEA, OID_TEXT,
-       OID_VARCHAR, OID_BOOL, OID_TEXT, OID_INT8 },
+       OID_VARCHAR, OID_BOOL, OID_BOOL, OID_TEXT, OID_INT8 },
      "insert_v4_host_option",
      "INSERT INTO dhcp4_options(code, value, formatted_value, space, "
-     "  persistent, user_context, host_id, scope_id) "
-     "VALUES ($1, $2, $3, $4, $5, $6, $7, 3)"
+     "  persistent, cancelled, user_context, host_id, scope_id) "
+     "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 3)"
     },
 
     // PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION
     // Inserts a single DHCPv6 option into 'dhcp6_options' table.
     // Using fixed scope_id = 3, which associates an option with host.
-    {7,
+    {8,
      { OID_INT2, OID_BYTEA, OID_TEXT,
-       OID_VARCHAR, OID_BOOL, OID_TEXT, OID_INT8 },
+       OID_VARCHAR, OID_BOOL, OID_BOOL, OID_TEXT, OID_INT8 },
      "insert_v6_host_option",
      "INSERT INTO dhcp6_options(code, value, formatted_value, space, "
-     "  persistent, user_context, host_id, scope_id) "
-     "VALUES ($1, $2, $3, $4, $5, $6, $7, 3)"
+     "  persistent, cancelled, user_context, host_id, scope_id) "
+     "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 3)"
     },
 
     // PgSqlHostDataSourceImpl::DEL_HOST_ADDR4
index 43a2f79c62a3b8f80398b4b7f499e6b9f4eac4b6..8c67343ae02f749ee1659c6971119e2ef9e54c6b 100644 (file)
@@ -337,7 +337,8 @@ public:
         // Insert global options into the database.
         OptionDescriptorPtr opt(new OptionDescriptor(createOption<OptionString>
                                                      (Option::V4, DHO_HOST_NAME,
-                                                      true, false, "new.example.com")));
+                                                      true, false, false,
+                                                      "new.example.com")));
         opt->setId(1);
         opt->space_name_ = DHCP4_OPTION_SPACE;
         opt->setModificationTime(getTimestamp("dhcp4_options"));
@@ -346,7 +347,7 @@ public:
 
         opt.reset(new OptionDescriptor(createOption<OptionString>
                                        (Option::V4, DHO_TFTP_SERVER_NAME,
-                                        true, false, "tftp-my")));
+                                        true, false, false, "tftp-my")));
         opt->setId(2);
         opt->space_name_ = DHCP4_OPTION_SPACE;
         opt->setModificationTime(getTimestamp("dhcp4_options"));
@@ -389,7 +390,10 @@ public:
 
         // Add a standard option to the class.
         OptionPtr option = Option::create(Option::V4, DHO_BOOT_FILE_NAME);
-        OptionDescriptorPtr desc = OptionDescriptor::create(option, true, "bogus-file.txt");
+        OptionDescriptorPtr desc = OptionDescriptor::create(option,
+                                                            true,
+                                                            false,
+                                                            "bogus-file.txt");
         desc->space_name_ = DHCP4_OPTION_SPACE;
         desc->setModificationTime(getTimestamp("dhcp4_client_class"));
         client_class->getCfgOption()->add(*desc, desc->space_name_);
@@ -404,7 +408,7 @@ public:
 
         // Add a custom option to the class.
         option = Option::create(Option::V4, 201);
-        desc = OptionDescriptor::create(option, true, "custom-stuff");
+        desc = OptionDescriptor::create(option, true, false, "custom-stuff");
         desc->space_name_ = "isc";
         desc->setModificationTime(getTimestamp("dhcp4_client_class"));
         client_class->getCfgOption()->add(*desc, desc->space_name_);
@@ -1173,7 +1177,8 @@ public:
         // Insert global options into the database.
         OptionDescriptorPtr opt(new OptionDescriptor(createOption<OptionString>
                                                      (Option::V6, D6O_BOOTFILE_URL,
-                                                      true, false, "some.bootfile")));
+                                                      true, false, false,
+                                                      "some.bootfile")));
         opt->setId(1);
         opt->space_name_ = DHCP6_OPTION_SPACE;
         opt->setModificationTime(getTimestamp("dhcp6_options"));
@@ -1182,7 +1187,8 @@ public:
 
         opt.reset(new OptionDescriptor(createOption<OptionString>
                                        (Option::V6, D6O_AFTR_NAME,
-                                        true, true, "some.example.com")));
+                                        true, true, true,
+                                        "some.example.com")));
         opt->setId(2);
         opt->space_name_ = DHCP6_OPTION_SPACE;
         opt->setModificationTime(getTimestamp("dhcp6_options"));
@@ -1225,7 +1231,9 @@ public:
 
         // Add an option to the class.
         OptionPtr option = Option::create(Option::V6, D6O_BOOTFILE_URL);
-        OptionDescriptorPtr desc = OptionDescriptor::create(option, true, "client.boot.url");
+        OptionDescriptorPtr desc = OptionDescriptor::create(option, true,
+                                                            false,
+                                                            "client.boot.url");
         desc->space_name_ = DHCP6_OPTION_SPACE;
         desc->setModificationTime(getTimestamp("dhcp6_client_class"));
         client_class->getCfgOption()->add(*desc, desc->space_name_);
index b6692d20cc5ffb7340fa39e704872580625ab345..acc3ca67aa109c9014de77ab837ba3c15ec14603 100644 (file)
@@ -38,11 +38,12 @@ TEST(OptionDescriptorTest, create) {
     OptionPtr option = Option::create(Option::V4, 234);
     ElementPtr context = Element::createMap();
     context->set("name", Element::create("value"));
-    auto desc = OptionDescriptor::create(option, true, "value", context);
+    auto desc = OptionDescriptor::create(option, true, true, "value", context);
 
     ASSERT_TRUE(desc);
     EXPECT_EQ(option, desc->option_);
     EXPECT_TRUE(desc->persistent_);
+    EXPECT_TRUE(desc->cancelled_);
     EXPECT_EQ("value", desc->formatted_value_);
     EXPECT_EQ(context, desc->getContext());
 }
@@ -50,11 +51,12 @@ TEST(OptionDescriptorTest, create) {
 // This test verifies that the OptionDescriptor factory function variant
 // taking persistent flag as an argument creates valid instance.
 TEST(OptionDescriptorTest, createPersistent) {
-    auto desc = OptionDescriptor::create(true);
+    auto desc = OptionDescriptor::create(true, true);
     ASSERT_TRUE(desc);
 
     EXPECT_FALSE(desc->option_);
     EXPECT_TRUE(desc->persistent_);
+    EXPECT_TRUE(desc->cancelled_);
     EXPECT_TRUE(desc->formatted_value_.empty());
     EXPECT_FALSE(desc->getContext());
 }
@@ -65,7 +67,7 @@ TEST(OptionDescriptorTest, createCopy) {
     OptionPtr option = Option::create(Option::V4, 234);
     ElementPtr context = Element::createMap();
     context->set("name", Element::create("value"));
-    auto desc = OptionDescriptor::create(option, true, "value", context);
+    auto desc = OptionDescriptor::create(option, true, true, "value", context);
 
     auto desc_copy = OptionDescriptor::create(*desc);
     ASSERT_TRUE(desc_copy);
@@ -73,6 +75,7 @@ TEST(OptionDescriptorTest, createCopy) {
     ASSERT_TRUE(desc_copy);
     EXPECT_EQ(option, desc_copy->option_);
     EXPECT_TRUE(desc_copy->persistent_);
+    EXPECT_TRUE(desc_copy->cancelled_);
     EXPECT_EQ("value", desc_copy->formatted_value_);
     EXPECT_EQ(context, desc_copy->getContext());
 }
@@ -81,14 +84,15 @@ TEST(OptionDescriptorTest, createCopy) {
 // does the shallow copy.
 TEST(OptionDescriptorTest, assign) {
     // Create a persistent option descriptor.
-    auto desc = OptionDescriptor::create(true);
+    auto desc = OptionDescriptor::create(true, true);
     ASSERT_TRUE(desc);
 
     // Create another option descriptor.
     OptionPtr option = Option::create(Option::V4, 234);
     ElementPtr context = Element::createMap();
     context->set("name", Element::create("value"));
-    auto desc1 = OptionDescriptor::create(option, true, "value", context);
+    auto desc1 = OptionDescriptor::create(option, false, false,  "value",
+                                          context);
     ASSERT_TRUE(desc1);
 
     // Assign the option descriptor.
@@ -97,7 +101,8 @@ TEST(OptionDescriptorTest, assign) {
     // Check it.
     ASSERT_TRUE(desc);
     EXPECT_EQ(option, desc->option_);
-    EXPECT_TRUE(desc->persistent_);
+    EXPECT_FALSE(desc->persistent_);
+    EXPECT_FALSE(desc->cancelled_);
     EXPECT_EQ("value", desc->formatted_value_);
     EXPECT_EQ(context, desc->getContext());
 }
@@ -125,7 +130,7 @@ public:
 
             // In order to easier identify the options by id, let's use the option
             // code as the id.
-            ASSERT_NO_THROW(cfg.add(option, false, DHCP6_OPTION_SPACE,
+            ASSERT_NO_THROW(cfg.add(option, false, false, DHCP6_OPTION_SPACE,
                                     static_cast<uint64_t>(code)));
         }
 
@@ -134,7 +139,7 @@ public:
             OptionUint16Ptr option = OptionUint16Ptr(new OptionUint16(Option::V6,
                                                                       code, 2345));
             option->setEncapsulatedSpace("bar");
-            ASSERT_NO_THROW(cfg.add(option, false, DHCP6_OPTION_SPACE,
+            ASSERT_NO_THROW(cfg.add(option, false, false, DHCP6_OPTION_SPACE,
                                     static_cast<uint64_t>(code)));
         }
 
@@ -144,7 +149,8 @@ public:
             OptionUint8Ptr option = OptionUint8Ptr(new OptionUint8(Option::V6, code,
                                                                    0x01));
             option->setEncapsulatedSpace("foo-subs");
-            ASSERT_NO_THROW(cfg.add(option, false, "foo", static_cast<uint64_t>(code)));
+            ASSERT_NO_THROW(cfg.add(option, false, false, "foo",
+                                    static_cast<uint64_t>(code)));
         }
 
         // Create sub-options belonging to "bar" option space and encapsulating
@@ -153,14 +159,15 @@ public:
             OptionUint8Ptr option = OptionUint8Ptr(new OptionUint8(Option::V6,
                                                                    code, 0x02));
             option->setEncapsulatedSpace("bar-subs");
-            ASSERT_NO_THROW(cfg.add(option, false, "bar", static_cast<uint64_t>(code)));
+            ASSERT_NO_THROW(cfg.add(option, false, false, "bar",
+                                    static_cast<uint64_t>(code)));
         }
 
         // Create sub-options belonging to "foo-subs" option space.
         for (uint16_t code = 1; code < 10; ++code) {
             OptionUint8Ptr option = OptionUint8Ptr(new OptionUint8(Option::V6, code,
                                                                    0x03));
-            ASSERT_NO_THROW(cfg.add(option, false, "foo-subs",
+            ASSERT_NO_THROW(cfg.add(option, false, false, "foo-subs",
                                     static_cast<uint64_t>(code)));
         }
 
@@ -168,7 +175,7 @@ public:
         for (uint16_t code = 501;  code < 510; ++code) {
             OptionUint8Ptr option = OptionUint8Ptr(new OptionUint8(Option::V6,
                                                                    code, 0x04));
-            ASSERT_NO_THROW(cfg.add(option, false, "bar-subs",
+            ASSERT_NO_THROW(cfg.add(option, false, false, "bar-subs",
                                     static_cast<uint64_t>(code)));
         }
     }
@@ -185,8 +192,8 @@ TEST_F(CfgOptionTest, empty) {
 
     // Add an option to each configuration
     OptionPtr option(new Option(Option::V6, 1));
-    ASSERT_NO_THROW(cfg1.add(option, false, DHCP6_OPTION_SPACE));
-    ASSERT_NO_THROW(cfg2.add(option, true, "isc"));
+    ASSERT_NO_THROW(cfg1.add(option, false, false, DHCP6_OPTION_SPACE));
+    ASSERT_NO_THROW(cfg2.add(option, true, true, "isc"));
 
     // The first option configuration has an option
     ASSERT_FALSE(cfg1.empty());
@@ -208,8 +215,8 @@ TEST_F(CfgOptionTest, equals) {
     // option code and content.
     for (uint16_t code = 1; code < 10; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, code)));
-        ASSERT_NO_THROW(cfg1.add(option, false, "isc"));
-        ASSERT_NO_THROW(cfg1.add(option, true, "vendor-123"));
+        ASSERT_NO_THROW(cfg1.add(option, false, false, "isc"));
+        ASSERT_NO_THROW(cfg1.add(option, true, true, "vendor-123"));
     }
 
     // Configurations should now be different.
@@ -220,8 +227,8 @@ TEST_F(CfgOptionTest, equals) {
     // spaces.
     for (uint16_t code = 2; code < 10; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, code)));
-        ASSERT_NO_THROW(cfg2.add(option, false, "isc"));
-        ASSERT_NO_THROW(cfg2.add(option, true, "vendor-123"));
+        ASSERT_NO_THROW(cfg2.add(option, false, false, "isc"));
+        ASSERT_NO_THROW(cfg2.add(option, true, true, "vendor-123"));
     }
 
     // Configurations should still be unequal.
@@ -231,7 +238,7 @@ TEST_F(CfgOptionTest, equals) {
     // Add missing option to the option space isc.
     ASSERT_NO_THROW(cfg2.add(OptionPtr(new Option(Option::V6, 1,
                                                   OptionBuffer(10, 0x01))),
-                             false, "isc"));
+                             false, false, "isc"));
     // Configurations should still be unequal because option with code 1
     // is missing in the option space vendor-123.
     ASSERT_FALSE(cfg1 == cfg2);
@@ -240,11 +247,10 @@ TEST_F(CfgOptionTest, equals) {
     // Add missing option.
     ASSERT_NO_THROW(cfg2.add(OptionPtr(new Option(Option::V6, 1,
                                                   OptionBuffer(10, 0x01))),
-                             true, "vendor-123"));
+                             true, true, "vendor-123"));
     // Configurations should now be equal.
     ASSERT_TRUE(cfg1 == cfg2);
     ASSERT_FALSE(cfg1 != cfg2);
-
 }
 
 // This test verifies that multiple options can be added to the configuration
@@ -255,14 +261,14 @@ TEST_F(CfgOptionTest, add) {
     // Differentiate options by their codes (100-109)
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(cfg.add(option, false, DHCP6_OPTION_SPACE));
+        ASSERT_NO_THROW(cfg.add(option, false, false, DHCP6_OPTION_SPACE));
     }
 
     // Add 7 options to another option space. The option codes partially overlap
     // with option codes that we have added to dhcp6 option space.
     for (uint16_t code = 105; code < 112; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(cfg.add(option, false, "isc"));
+        ASSERT_NO_THROW(cfg.add(option, false, false, "isc"));
     }
 
     // Get options from the Subnet and check if all 10 are there.
@@ -304,13 +310,13 @@ TEST_F(CfgOptionTest, replace) {
 
     // Let's add some options to the config to the config.
     OptionStringPtr option(new OptionString(Option::V6, 1, "one"));
-    ASSERT_NO_THROW(cfg.add(option, false, "isc"));
+    ASSERT_NO_THROW(cfg.add(option, false, false, "isc"));
 
     option.reset(new OptionString(Option::V6, 2, "two"));
-    ASSERT_NO_THROW(cfg.add(option, false, "isc"));
+    ASSERT_NO_THROW(cfg.add(option, false, false, "isc"));
 
     option.reset(new OptionString(Option::V6, 3, "three"));
-    ASSERT_NO_THROW(cfg.add(option, false, "isc"));
+    ASSERT_NO_THROW(cfg.add(option, false, false, "isc"));
 
     // Now let's make sure we can find them and they are as expected.
     OptionDescriptor desc = cfg.get("isc", 1);
@@ -367,14 +373,14 @@ TEST_F(CfgOptionTest, mergeTo) {
     // from the range of 100 to 109 and holding one byte of data equal to 0xFF.
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF)));
-        ASSERT_NO_THROW(cfg_src.add(option, false, DHCP6_OPTION_SPACE));
+        ASSERT_NO_THROW(cfg_src.add(option, false, false, DHCP6_OPTION_SPACE));
     }
 
     // Create collection of options in vendor space 123, with option codes
     // from the range of 100 to 109 and holding one byte of data equal to 0xFF.
     for (uint16_t code = 100; code < 110; code += 2) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF)));
-        ASSERT_NO_THROW(cfg_src.add(option, false, "vendor-123"));
+        ASSERT_NO_THROW(cfg_src.add(option, false, false, "vendor-123"));
     }
 
     // Create destination configuration (configuration that we merge the
@@ -384,14 +390,14 @@ TEST_F(CfgOptionTest, mergeTo) {
     // 100 to 108.
     for (uint16_t code = 100; code < 110; code += 2) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0x01)));
-        ASSERT_NO_THROW(cfg_dst.add(option, false, DHCP6_OPTION_SPACE));
+        ASSERT_NO_THROW(cfg_dst.add(option, false, false, DHCP6_OPTION_SPACE));
     }
 
     // Create collection of options having odd option codes in the range of
     // 101 to 109.
     for (uint16_t code = 101; code < 110; code += 2) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0x01)));
-        ASSERT_NO_THROW(cfg_dst.add(option, false, "vendor-123"));
+        ASSERT_NO_THROW(cfg_dst.add(option, false, false, "vendor-123"));
     }
 
     // Merge source configuration to the destination configuration. The options
@@ -439,14 +445,14 @@ TEST_F(CfgOptionTest, copy) {
     // Add 10 options to the custom option space in the source configuration.
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0x01)));
-        ASSERT_NO_THROW(cfg_src.add(option, false, "foo"));
+        ASSERT_NO_THROW(cfg_src.add(option, false, false, "foo"));
     }
 
     CfgOption cfg_dst;
     // Add 20 options to the custom option space in destination configuration.
     for (uint16_t code = 100; code < 120; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF)));
-        ASSERT_NO_THROW(cfg_dst.add(option, false, "isc"));
+        ASSERT_NO_THROW(cfg_dst.add(option, false, false, "isc"));
     }
 
     // Copy entire configuration to the destination. This should override any
@@ -492,28 +498,28 @@ TEST_F(CfgOptionTest, validMerge) {
 
     // Create our existing config, that gets merged into.
     OptionPtr option(new Option(Option::V4, 1, OptionBuffer(1, 0x01)));
-    ASSERT_NO_THROW(this_cfg.add(option, false, "isc"));
+    ASSERT_NO_THROW(this_cfg.add(option, false, false, "isc"));
 
     // Add option 3 to "fluff"
     option.reset(new Option(Option::V4, 3, OptionBuffer(1, 0x03)));
-    ASSERT_NO_THROW(this_cfg.add(option, false, "fluff"));
+    ASSERT_NO_THROW(this_cfg.add(option, false, false, "fluff"));
 
     // Add option 4 to "fluff".
     option.reset(new Option(Option::V4, 4, OptionBuffer(1, 0x04)));
-    ASSERT_NO_THROW(this_cfg.add(option, false, "fluff"));
+    ASSERT_NO_THROW(this_cfg.add(option, false, false, "fluff"));
 
     // Create our other config that will be merged from.
     // Add Option 1 to "isc",  this should "overwrite" the original.
     option.reset(new Option(Option::V4, 1, OptionBuffer(1, 0x10)));
-    ASSERT_NO_THROW(other_cfg.add(option, false, "isc"));
+    ASSERT_NO_THROW(other_cfg.add(option, false, false, "isc"));
 
     // Add option 2  to "isc".
     option.reset(new Option(Option::V4, 2, OptionBuffer(1, 0x20)));
-    ASSERT_NO_THROW(other_cfg.add(option, false, "isc"));
+    ASSERT_NO_THROW(other_cfg.add(option, false, false, "isc"));
 
     // Add option 4 to "isc".
     option.reset(new Option(Option::V4, 4, OptionBuffer(1, 0x40)));
-    ASSERT_NO_THROW(other_cfg.add(option, false, "isc"));
+    ASSERT_NO_THROW(other_cfg.add(option, false, false, "isc"));
 
     // Merge source configuration to the destination configuration. The options
     // in the destination should be preserved. The options from the source
@@ -569,11 +575,11 @@ TEST_F(CfgOptionTest, mergeInvalid) {
     // Create our other config that will be merged from.
     // Add an option without a formatted value.
     OptionPtr option(new Option(Option::V4, 1, OptionBuffer(1, 0x01)));
-    ASSERT_NO_THROW(other_cfg.add(option, false, "isc"));
+    ASSERT_NO_THROW(other_cfg.add(option, false, false, "isc"));
 
     // Add an option with a formatted value.
     option.reset(new Option(Option::V4, 2));
-    OptionDescriptor desc(option, false, "one,two,three");
+    OptionDescriptor desc(option, false, false, "one,two,three");
     ASSERT_NO_THROW(other_cfg.add(desc, "isc"));
 
     // When we attempt to merge, it should fail, recognizing that
@@ -612,7 +618,7 @@ TEST_F(CfgOptionTest, createDescriptorOptionValid) {
     std::string value = "v4.example.com";
     OptionPtr option(new Option(Option::V6, DHO_HOST_NAME));
     option->setData(value.begin(), value.end());
-    OptionDescriptorPtr desc(new OptionDescriptor(option, false));
+    OptionDescriptorPtr desc(new OptionDescriptor(option, false, false));
 
     bool updated = false;
     ASSERT_NO_THROW(updated = CfgOption::createDescriptorOption(defs, space, *desc));
@@ -627,7 +633,7 @@ TEST_F(CfgOptionTest, createDescriptorOptionValid) {
         { 2, 'v', '6', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0 };
     option.reset(new Option(Option::V6, D6O_AFTR_NAME));
     option->setData(fqdn.begin(), fqdn.end());
-    desc.reset(new OptionDescriptor(option, false));
+    desc.reset(new OptionDescriptor(option, false, false));
 
     ASSERT_NO_THROW(updated = CfgOption::createDescriptorOption(defs, space, *desc));
     ASSERT_TRUE(updated);
@@ -639,7 +645,7 @@ TEST_F(CfgOptionTest, createDescriptorOptionValid) {
     space = "vendor-4491";
     value = "192.0.2.1, 192.0.2.2";
     option.reset(new Option(Option::V4, 2));
-    desc.reset(new OptionDescriptor(option, false, value));
+    desc.reset(new OptionDescriptor(option, false, false, value));
 
     ASSERT_NO_THROW(updated = CfgOption::createDescriptorOption(defs, space, *desc));
     ASSERT_TRUE(updated);
@@ -651,7 +657,7 @@ TEST_F(CfgOptionTest, createDescriptorOptionValid) {
     // Now, a user defined uint8 option
     space = "isc";
     option.reset(new Option(Option::V4, 1, OptionBuffer(1, 0x77)));
-    desc.reset(new OptionDescriptor(option, false));
+    desc.reset(new OptionDescriptor(option, false, false));
 
     ASSERT_NO_THROW(updated = CfgOption::createDescriptorOption(defs, space, *desc));
     ASSERT_TRUE(updated);
@@ -661,7 +667,7 @@ TEST_F(CfgOptionTest, createDescriptorOptionValid) {
 
     // Now, a user defined array of ints from a formatted value
     option.reset(new Option(Option::V4, 2));
-    desc.reset(new OptionDescriptor(option, false, "1,2,3"));
+    desc.reset(new OptionDescriptor(option, false, false, "1,2,3"));
 
     ASSERT_NO_THROW(updated = CfgOption::createDescriptorOption(defs, space, *desc));
     ASSERT_TRUE(updated);
@@ -672,7 +678,7 @@ TEST_F(CfgOptionTest, createDescriptorOptionValid) {
 
     // Finally, a generic, undefined option
     option.reset(new Option(Option::V4, 199, OptionBuffer(1, 0x77)));
-    desc.reset(new OptionDescriptor(option, false));
+    desc.reset(new OptionDescriptor(option, false, false));
 
     ASSERT_NO_THROW(updated = CfgOption::createDescriptorOption(defs, space, *desc));
     ASSERT_FALSE(updated);
@@ -769,7 +775,7 @@ TEST_F(CfgOptionTest, deleteOptions) {
     // Because we called "encapsulate", this option should have been
     // propagated to the options encapsulating option space "foo".
     for (uint16_t code = 1000; code < 1020; ++code) {
-        OptionDescriptor top_level_option(false);
+        OptionDescriptor top_level_option(false, false);
         ASSERT_NO_THROW(top_level_option = cfg.get(DHCP6_OPTION_SPACE, code));
         // Make sure that the option with code 5 is there.
         ASSERT_TRUE(top_level_option.option_);
@@ -798,7 +804,7 @@ TEST_F(CfgOptionTest, deleteOptions) {
     // Iterate over the options encapsulating "foo" option space. Make sure
     // that the option with code 5 is no longer encapsulated by these options.
     for (uint16_t code = 1000; code < 1020; ++code) {
-        OptionDescriptor top_level_option(false);
+        OptionDescriptor top_level_option(false, false);
         ASSERT_NO_THROW(top_level_option = cfg.get(DHCP6_OPTION_SPACE, code));
         ASSERT_TRUE(top_level_option.option_);
         EXPECT_FALSE(top_level_option.option_->getOption(5));
@@ -838,7 +844,8 @@ TEST_F(CfgOptionTest, deleteOptionsById) {
     // Create multiple vendor options for vendor id 123.
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF)));
-        ASSERT_NO_THROW(cfg.add(option, false, "vendor-123", static_cast<uint64_t>(code)));
+        ASSERT_NO_THROW(cfg.add(option, false, false, "vendor-123",
+                                static_cast<uint64_t>(code)));
     }
 
     // Delete options with id of 100. It includes both regular options and
@@ -876,13 +883,13 @@ TEST_F(CfgOptionTest, delVendorOption) {
     // Create multiple vendor options for vendor id 123.
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF)));
-        ASSERT_NO_THROW(cfg.add(option, false, "vendor-123"));
+        ASSERT_NO_THROW(cfg.add(option, false, false, "vendor-123"));
     }
 
     // Create multiple vendor options for vendor id 234.
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF)));
-        ASSERT_NO_THROW(cfg.add(option, false, "vendor-234"));
+        ASSERT_NO_THROW(cfg.add(option, false, false, "vendor-234"));
     }
 
     // Make sure that the option we're trying to delete is there.
@@ -912,7 +919,7 @@ TEST_F(CfgOptionTest, get) {
     // Add 10 options to a "dhcp6" option space in the subnet.
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(cfg.add(option, false, DHCP6_OPTION_SPACE));
+        ASSERT_NO_THROW(cfg.add(option, false, false, DHCP6_OPTION_SPACE));
     }
 
     // Check that we can get each added option descriptor using
@@ -939,9 +946,9 @@ TEST_F(CfgOptionTest, getList) {
     // Add twice 10 options to a "dhcp4" option space in the subnet.
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(cfg.add(option, false, DHCP4_OPTION_SPACE));
+        ASSERT_NO_THROW(cfg.add(option, false, false, DHCP4_OPTION_SPACE));
         OptionPtr option2(new Option(Option::V4, code, OptionBuffer(10, 0xEE)));
-        ASSERT_NO_THROW(cfg.add(option2, false, DHCP4_OPTION_SPACE));
+        ASSERT_NO_THROW(cfg.add(option2, false, false, DHCP4_OPTION_SPACE));
     }
 
     // Check that we can get each added option descriptors.
@@ -984,9 +991,9 @@ TEST_F(CfgOptionTest, getListVendor) {
     // Add twice 10 options to a "dhcp4" option space in the subnet.
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(cfg.add(option, false, vendor_space));
+        ASSERT_NO_THROW(cfg.add(option, false, false, vendor_space));
         OptionPtr option2(new Option(Option::V4, code, OptionBuffer(10, 0xEE)));
-        ASSERT_NO_THROW(cfg.add(option2, false, vendor_space));
+        ASSERT_NO_THROW(cfg.add(option2, false, false, vendor_space));
     }
 
     // Check that we can get each added option descriptors.
@@ -1030,7 +1037,7 @@ TEST_F(CfgOptionTest, addNonUniqueOptions) {
         // In the inner loop we create options with unique codes (100-109).
         for (uint16_t code = 100; code < 110; ++code) {
             OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-            ASSERT_NO_THROW(cfg.add(option, false, DHCP6_OPTION_SPACE));
+            ASSERT_NO_THROW(cfg.add(option, false, false, DHCP6_OPTION_SPACE));
         }
     }
 
@@ -1080,7 +1087,7 @@ TEST(Subnet6Test, addPersistentOption) {
         // and options with these codes will be flagged non-persistent.
         // Options with other codes will be flagged persistent.
         bool persistent = (code % 3) ? true : false;
-        ASSERT_NO_THROW(cfg.add(option, persistent, DHCP6_OPTION_SPACE));
+        ASSERT_NO_THROW(cfg.add(option, persistent, true, DHCP6_OPTION_SPACE));
     }
 
     // Get added options from the subnet.
@@ -1101,6 +1108,45 @@ TEST(Subnet6Test, addPersistentOption) {
     ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
 }
 
+// This test verifies that the option with the cancellation flag can be
+// added to the configuration and that options with the cancellation flags
+// can be retrieved.
+TEST(Subnet6Test, addCancelledOption) {
+    CfgOption cfg;
+
+    // Add 10 options to the subnet with option codes 100 - 109.
+    for (uint16_t code = 100; code < 110; ++code) {
+        OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+        // We create 10 options and want some of them to be flagged
+        // cancelled and some non-cancelled. Cancelled options are
+        // those that server must never send to clients.
+        // We pick 3 out of 10 options and mark them
+        // non-cancelled and 7 other options cancelled.
+        // Code values: 102, 105 and 108 are divisible by 3
+        // and options with these codes will be flagged non-cancelled.
+        // Options with other codes will be flagged cancelled.
+        bool cancelled = (code % 3) ? true : false;
+        ASSERT_NO_THROW(cfg.add(option, true, cancelled, DHCP6_OPTION_SPACE));
+    }
+
+    // Get added options from the subnet.
+    OptionContainerPtr options = cfg.getAll(DHCP6_OPTION_SPACE);
+
+    // options->get<2> returns reference to container index #5. This
+    // index is used to access options by the 'cancelled' flag.
+    OptionContainerCancelIndex& idx = options->get<5>();
+
+    // Get all cancelled options->
+    OptionContainerCancelRange range_cancelled = idx.equal_range(true);
+    // 7 out of 10 options have been flagged cancelled.
+    ASSERT_EQ(7, distance(range_cancelled.first, range_cancelled.second));
+
+    // Get all non-cancelled options->
+    OptionContainerCancelRange range_non_cancelled = idx.equal_range(false);
+    // 3 out of 10 options have been flagged not cancelled.
+    ASSERT_EQ(3, distance(range_non_cancelled.first, range_non_cancelled.second));
+}
+
 // This test verifies that the vendor option can be added to the configuration.
 TEST_F(CfgOptionTest, addVendorOptions) {
     CfgOption cfg;
@@ -1108,7 +1154,7 @@ TEST_F(CfgOptionTest, addVendorOptions) {
     // Differentiate options by their codes (100-109)
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(cfg.add(option, false, "vendor-12345678"));
+        ASSERT_NO_THROW(cfg.add(option, false, false, "vendor-12345678"));
     }
 
     // Second option space uses corner case value for vendor id = max uint8.
@@ -1120,7 +1166,7 @@ TEST_F(CfgOptionTest, addVendorOptions) {
     // with option codes that we have added to dhcp6 option space.
     for (uint16_t code = 105; code < 112; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(cfg.add(option, false, option_space.str()));
+        ASSERT_NO_THROW(cfg.add(option, false, false, option_space.str()));
     }
 
     // Get options from the Subnet and check if all 10 are there.
@@ -1167,7 +1213,7 @@ TEST_F(CfgOptionTest, getVendorIdsSpaceNames) {
         // Generate space name for a unique vendor id.
         std::ostringstream s;
         s << "vendor-" << code;
-        ASSERT_NO_THROW(cfg.add(option, false, s.str()));
+        ASSERT_NO_THROW(cfg.add(option, false, false, s.str()));
     }
 
     // We should now have 10 different vendor ids.
@@ -1191,16 +1237,18 @@ TEST_F(CfgOptionTest, unparse) {
 
     // Add some options.
     OptionPtr opt1(new Option(Option::V6, 100, OptionBuffer(4, 0x12)));
-    cfg.add(opt1, false, "dns");
+    cfg.add(opt1, false, true, "dns");
     OptionPtr opt2(new Option(Option::V6, 101, OptionBuffer(4, 12)));
-    OptionDescriptor desc2(opt2, false, "12, 12, 12, 12");
+    OptionDescriptor desc2(opt2, false, true, "12, 12, 12, 12");
     std::string ctx = "{ \"comment\": \"foo\", \"bar\": 1 }";
     desc2.setContext(data::Element::fromJSON(ctx));
     cfg.add(desc2, "dns");
     OptionPtr opt3(new Option(Option::V6, D6O_STATUS_CODE, OptionBuffer(2, 0)));
-    cfg.add(opt3, false, DHCP6_OPTION_SPACE);
+    cfg.add(opt3, false, false, DHCP6_OPTION_SPACE);
     OptionPtr opt4(new Option(Option::V6, 100, OptionBuffer(4, 0x21)));
-    cfg.add(opt4, true, "vendor-1234");
+    cfg.add(opt4, true, true, "vendor-1234");
+    OptionPtr opt5(new Option(Option::V6, 111));
+    cfg.add(opt5, false, true, "vendor-5678");
 
     // Unparse
     std::string expected = "[\n"
@@ -1209,13 +1257,15 @@ TEST_F(CfgOptionTest, unparse) {
         "    \"space\": \"dns\",\n"
         "    \"csv-format\": false,\n"
         "    \"data\": \"12121212\",\n"
-        "    \"always-send\": false\n"
+        "    \"always-send\": false,\n"
+        "    \"never-send\": true\n"
         "},{\n"
         "    \"code\": 101,\n"
         "    \"space\": \"dns\",\n"
         "    \"csv-format\": true,\n"
         "    \"data\": \"12, 12, 12, 12\",\n"
         "    \"always-send\": false,\n"
+        "    \"never-send\": true,\n"
         "    \"user-context\": { \"comment\": \"foo\", \"bar\": 1 }\n"
         "},{\n"
         "    \"code\": 13,\n"
@@ -1223,13 +1273,20 @@ TEST_F(CfgOptionTest, unparse) {
         "    \"space\": \"dhcp6\",\n"
         "    \"csv-format\": false,\n"
         "    \"data\": \"0000\",\n"
-        "    \"always-send\": false\n"
+        "    \"always-send\": false,\n"
+        "    \"never-send\": false\n"
         "},{\n"
         "    \"code\": 100,\n"
         "    \"space\": \"vendor-1234\",\n"
         "    \"csv-format\": false,\n"
         "    \"data\": \"21212121\",\n"
-        "    \"always-send\": true\n"
+        "    \"always-send\": true,\n"
+        "    \"never-send\": true\n"
+        "},{\n"
+        "    \"code\": 111,\n"
+        "    \"space\": \"vendor-5678\",\n"
+        "    \"always-send\": false,\n"
+        "    \"never-send\": true\n"
         "}]\n";
     isc::test::runToElementTest<CfgOption>(expected, cfg);
 }
index 4c49218f2ca4c551be42323deec7d9e17dadb7b3..9a1a7319316710279b77fcf3376728ae4ea551f2 100644 (file)
@@ -337,7 +337,7 @@ TEST(CfgSharedNetworks4Test, mergeNetworks) {
     std::string value("Yay!");
     OptionPtr option(new Option(Option::V4, 1));
     option->setData(value.begin(), value.end());
-    ASSERT_NO_THROW(network1b->getCfgOption()->add(option, false, "isc"));
+    ASSERT_NO_THROW(network1b->getCfgOption()->add(option, false, false, "isc"));
     ASSERT_NO_THROW(network1b->add(subnet4));
 
     // Network2 we will not touch.
index 53a2fa8bb116eef1b7e270421fdb98fabf36eca8..57e1053b12e5033f7c3b540b6ce4dbe3055c82a2 100644 (file)
@@ -346,7 +346,7 @@ TEST(CfgSharedNetworks6Test, mergeNetworks) {
     std::string value("Yay!");
     OptionPtr option(new Option(Option::V6, 1));
     option->setData(value.begin(), value.end());
-    ASSERT_NO_THROW(network1b->getCfgOption()->add(option, false, "isc"));
+    ASSERT_NO_THROW(network1b->getCfgOption()->add(option, false, false, "isc"));
     ASSERT_NO_THROW(network1b->add(subnet4));
 
     // Network2 we will not touch.
index da23ec3a04dadc1d02aab8a93a6109c1200a1010..788ad0f51e22727db944a79f643acad4839f0d21 100644 (file)
@@ -313,7 +313,7 @@ TEST(CfgSubnets4Test, mergeSubnets) {
     std::string value("Yay!");
     OptionPtr option(new Option(Option::V4, 1));
     option->setData(value.begin(), value.end());
-    ASSERT_NO_THROW(subnet1b->getCfgOption()->add(option, false, "isc"));
+    ASSERT_NO_THROW(subnet1b->getCfgOption()->add(option, false, false, "isc"));
 
     // subnet 3b updates subnet 3 with different ID and removes it
     // from network 2
@@ -324,7 +324,7 @@ TEST(CfgSubnets4Test, mergeSubnets) {
     value = "Team!";
     option.reset(new Option(Option::V4, 1));
     option->setData(value.begin(), value.end());
-    ASSERT_NO_THROW(subnet3b->getCfgOption()->add(option, false, "isc"));
+    ASSERT_NO_THROW(subnet3b->getCfgOption()->add(option, false, false, "isc"));
 
     // subnet 4b updates subnet 4 and moves it from network2 to network 1
     Subnet4Ptr subnet4b(new Subnet4(IOAddress("192.0.4.0"),
@@ -342,7 +342,7 @@ TEST(CfgSubnets4Test, mergeSubnets) {
     value = "POOLS";
     option.reset(new Option(Option::V4, 1));
     option->setData(value.begin(), value.end());
-    ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "isc"));
+    ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, false, "isc"));
     subnet5->addPool(pool);
 
     // Add pool 2
@@ -350,7 +350,7 @@ TEST(CfgSubnets4Test, mergeSubnets) {
     value ="RULE!";
     option.reset(new Option(Option::V4, 1));
     option->setData(value.begin(), value.end());
-    ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "isc"));
+    ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, false, "isc"));
     subnet5->addPool(pool);
 
     // Add subnets to the merge from config.
@@ -1258,7 +1258,8 @@ TEST(CfgSubnets4Test, hasSubnetWithServerId) {
     OptionCustomPtr opt_server_id(new OptionCustom(*def, Option::V4));
     opt_server_id->writeAddress(IOAddress("1.2.3.4"));
     Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3, 100));
-    subnet->getCfgOption()->add(opt_server_id, false, DHCP4_OPTION_SPACE);
+    subnet->getCfgOption()->add(opt_server_id, false, false,
+                                DHCP4_OPTION_SPACE);
     cfg.add(subnet);
 
     EXPECT_TRUE(cfg.hasSubnetWithServerId(IOAddress("1.2.3.4")));
index c86e190091a54f1af378467ea55157d2c0b239e9..b9762c8b82f7e93417d7c4349756db1d59810f6d 100644 (file)
@@ -975,7 +975,7 @@ TEST(CfgSubnets6Test, mergeSubnets) {
     std::string value("Yay!");
     OptionPtr option(new Option(Option::V6, 1));
     option->setData(value.begin(), value.end());
-    ASSERT_NO_THROW(subnet1b->getCfgOption()->add(option, false, "isc"));
+    ASSERT_NO_THROW(subnet1b->getCfgOption()->add(option, false, false, "isc"));
 
     // subnet 3b updates subnet 3 with different UD and removes it
     // from network 2
@@ -986,7 +986,7 @@ TEST(CfgSubnets6Test, mergeSubnets) {
     value = "Team!";
     option.reset(new Option(Option::V6, 1));
     option->setData(value.begin(), value.end());
-    ASSERT_NO_THROW(subnet3b->getCfgOption()->add(option, false, "isc"));
+    ASSERT_NO_THROW(subnet3b->getCfgOption()->add(option, false, false, "isc"));
 
     // subnet 4b updates subnet 4 and moves it from network2 to network 1
     Subnet6Ptr subnet4b(new Subnet6(IOAddress("2001:4::"),
@@ -1004,7 +1004,7 @@ TEST(CfgSubnets6Test, mergeSubnets) {
     value = "POOLS";
     option.reset(new Option(Option::V6, 1));
     option->setData(value.begin(), value.end());
-    ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "isc"));
+    ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, false, "isc"));
     subnet5->addPool(pool);
 
     // Add pool 2
@@ -1012,7 +1012,7 @@ TEST(CfgSubnets6Test, mergeSubnets) {
     value ="RULE!";
     option.reset(new Option(Option::V6, 1));
     option->setData(value.begin(), value.end());
-    ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "isc"));
+    ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, false, "isc"));
     subnet5->addPool(pool);
 
     // Add subnets to the merge from config.
index e7894a52c3484b9853e112e87ccc82a6b56743b6..e89696927b6ec02cf2339ae0b735785719a51bf5 100644 (file)
@@ -65,7 +65,7 @@ TEST(ClientClassDef, copyConstruction) {
 
     auto cfg_option = boost::make_shared<CfgOption>();
     auto option = boost::make_shared<Option>(Option::V6, 1024);
-    cfg_option->add(option, false, DHCP6_OPTION_SPACE);
+    cfg_option->add(option, false, false, DHCP6_OPTION_SPACE);
 
     auto option_def = boost::make_shared<OptionDefinition>("foo", 1024, "dhcp6", "empty");
     CfgOptionDefPtr cfg_option_def = boost::make_shared<CfgOptionDef>();
@@ -144,13 +144,15 @@ TEST(ClientClassDef, cfgOptionBasics) {
     OptionPtr option;
     test_options.reset(new CfgOption());
     option.reset(new Option(Option::V4, 17, OptionBuffer(10, 0xFF)));
-    ASSERT_NO_THROW(test_options->add(option, false, DHCP4_OPTION_SPACE));
+    ASSERT_NO_THROW(test_options->add(option, false, false,
+                                      DHCP4_OPTION_SPACE));
 
     option.reset(new Option(Option::V6, 101, OptionBuffer(10, 0xFF)));
-    ASSERT_NO_THROW(test_options->add(option, false, "isc"));
+    ASSERT_NO_THROW(test_options->add(option, false, false, "isc"));
 
     option.reset(new Option(Option::V6, 100, OptionBuffer(10, 0xFF)));
-    ASSERT_NO_THROW(test_options->add(option, false, DHCP6_OPTION_SPACE));
+    ASSERT_NO_THROW(test_options->add(option, false, false,
+                                      DHCP6_OPTION_SPACE));
 
     // Now remake the client class with cfg_option
     ASSERT_NO_THROW(cclass.reset(new ClientClassDef(name, expr, test_options)));
@@ -187,7 +189,8 @@ TEST(ClientClassDef, copyAndEquality) {
     OptionPtr option;
     test_options.reset(new CfgOption());
     option.reset(new Option(Option::V4, 17, OptionBuffer(10, 0xFF)));
-    ASSERT_NO_THROW(test_options->add(option, false, DHCP4_OPTION_SPACE));
+    ASSERT_NO_THROW(test_options->add(option, false, false,
+                                      DHCP4_OPTION_SPACE));
 
     // Now remake the client class with cfg_option
     ASSERT_NO_THROW(cclass.reset(new ClientClassDef("class_one", expr,
@@ -283,7 +286,8 @@ TEST(ClientClassDef, copyAndEquality) {
     // Make a class that with same name and expression, but different options
     // verify that the equality tools reflect that the classes are not equal.
     option.reset(new Option(Option::V4, 20, OptionBuffer(10, 0xFF)));
-    ASSERT_NO_THROW(test_options->add(option, false, DHCP4_OPTION_SPACE));
+    ASSERT_NO_THROW(test_options->add(option, false, false,
+                                      DHCP4_OPTION_SPACE));
     ASSERT_NO_THROW(cclass2.reset(new ClientClassDef("class_one", expr,
                                                      test_options)));
     EXPECT_FALSE(cclass->equals(*cclass2));
@@ -749,12 +753,13 @@ TEST(ClientClassDictionary, createOptions) {
     // Make some options for the second class.
     cfg_option.reset(new CfgOption());
     OptionPtr option = Option::create(Option::V4, DHO_BOOT_FILE_NAME);
-    OptionDescriptorPtr desc = OptionDescriptor::create(option, true, "bogus-file.txt");
+    OptionDescriptorPtr desc = OptionDescriptor::create(option, true, false,
+                                                        "bogus-file.txt");
     desc->space_name_ = DHCP4_OPTION_SPACE;
     cfg_option->add(*desc, desc->space_name_);
 
     option = Option::create(Option::V4, DHO_TFTP_SERVER_NAME);
-    desc = OptionDescriptor::create(option, true, "bogus-tftp-server");
+    desc = OptionDescriptor::create(option, true, false, "bogus-tftp-server");
     desc->space_name_ = DHCP4_OPTION_SPACE;
     cfg_option->add(*desc, desc->space_name_);
 
@@ -842,7 +847,7 @@ TEST(TemplateClientClassDef, copyConstruction) {
 
     auto cfg_option = boost::make_shared<CfgOption>();
     auto option = boost::make_shared<Option>(Option::V6, 1024);
-    cfg_option->add(option, false, DHCP6_OPTION_SPACE);
+    cfg_option->add(option, false, false, DHCP6_OPTION_SPACE);
 
     auto option_def = boost::make_shared<OptionDefinition>("foo", 1024, "dhcp6", "empty");
     CfgOptionDefPtr cfg_option_def = boost::make_shared<CfgOptionDef>();
@@ -921,13 +926,15 @@ TEST(TemplateClientClassDef, cfgOptionBasics) {
     OptionPtr option;
     test_options.reset(new CfgOption());
     option.reset(new Option(Option::V4, 17, OptionBuffer(10, 0xFF)));
-    ASSERT_NO_THROW(test_options->add(option, false, DHCP4_OPTION_SPACE));
+    ASSERT_NO_THROW(test_options->add(option, false, false,
+                                      DHCP4_OPTION_SPACE));
 
     option.reset(new Option(Option::V6, 101, OptionBuffer(10, 0xFF)));
-    ASSERT_NO_THROW(test_options->add(option, false, "isc"));
+    ASSERT_NO_THROW(test_options->add(option, false, false, "isc"));
 
     option.reset(new Option(Option::V6, 100, OptionBuffer(10, 0xFF)));
-    ASSERT_NO_THROW(test_options->add(option, false, DHCP6_OPTION_SPACE));
+    ASSERT_NO_THROW(test_options->add(option, false, false,
+                                      DHCP6_OPTION_SPACE));
 
     // Now remake the client class with cfg_option
     ASSERT_NO_THROW(cclass.reset(new ClientClassDef(name, expr, test_options)));
@@ -964,7 +971,8 @@ TEST(TemplateClientClassDef, copyAndEquality) {
     OptionPtr option;
     test_options.reset(new CfgOption());
     option.reset(new Option(Option::V4, 17, OptionBuffer(10, 0xFF)));
-    ASSERT_NO_THROW(test_options->add(option, false, DHCP4_OPTION_SPACE));
+    ASSERT_NO_THROW(test_options->add(option, false, false,
+                                      DHCP4_OPTION_SPACE));
 
     // Now remake the client class with cfg_option
     ASSERT_NO_THROW(cclass.reset(new TemplateClientClassDef("class_one", expr,
@@ -1060,7 +1068,8 @@ TEST(TemplateClientClassDef, copyAndEquality) {
     // Make a class that with same name and expression, but different options
     // verify that the equality tools reflect that the classes are not equal.
     option.reset(new Option(Option::V4, 20, OptionBuffer(10, 0xFF)));
-    ASSERT_NO_THROW(test_options->add(option, false, DHCP4_OPTION_SPACE));
+    ASSERT_NO_THROW(test_options->add(option, false, false,
+                                      DHCP4_OPTION_SPACE));
     ASSERT_NO_THROW(cclass2.reset(new TemplateClientClassDef("class_one", expr,
                                                              test_options)));
     EXPECT_FALSE(cclass->equals(*cclass2));
@@ -1602,12 +1611,13 @@ TEST(ClientClassDictionary, templateCreateOptions) {
     // Make some options for the second class.
     cfg_option.reset(new CfgOption());
     OptionPtr option = Option::create(Option::V4, DHO_BOOT_FILE_NAME);
-    OptionDescriptorPtr desc = OptionDescriptor::create(option, true, "bogus-file.txt");
+    OptionDescriptorPtr desc = OptionDescriptor::create(option, true, false,
+                                                        "bogus-file.txt");
     desc->space_name_ = DHCP4_OPTION_SPACE;
     cfg_option->add(*desc, desc->space_name_);
 
     option = Option::create(Option::V4, DHO_TFTP_SERVER_NAME);
-    desc = OptionDescriptor::create(option, true, "bogus-tftp-server");
+    desc = OptionDescriptor::create(option, true, false, "bogus-tftp-server");
     desc->space_name_ = DHCP4_OPTION_SPACE;
     cfg_option->add(*desc, desc->space_name_);
 
index 409dbd0dc7bd3419e201be585f1237dac3d91d21..038314500f7a0dddf5143dd69718178174734470 100644 (file)
@@ -511,14 +511,16 @@ const SimpleDefaults ParseConfigTest::OPTION4_DEF_DEFAULTS = {
 const SimpleDefaults ParseConfigTest::OPTION6_DEFAULTS = {
     { "space",        Element::string,  "dhcp6"},
     { "csv-format",   Element::boolean, "true"},
-    { "always-send",  Element::boolean,"false"}
+    { "always-send",  Element::boolean,"false"},
+    { "never-send",   Element::boolean,"false"}
 };
 
 /// This table defines default values for options in DHCPv4
 const SimpleDefaults ParseConfigTest::OPTION4_DEFAULTS = {
     { "space",        Element::string,  "dhcp4"},
     { "csv-format",   Element::boolean, "true"},
-    { "always-send",  Element::boolean, "false"}
+    { "always-send",  Element::boolean, "false"},
+    { "never-send",   Element::boolean, "false"}
 };
 
 /// This table defines default values for both DHCPv4 and DHCPv6
index a7c1de49e0e90583b5e453ece21a80add27c5268..f819d75d86f5be8971a7cf56478e8b1643877ef5 100644 (file)
@@ -1038,7 +1038,8 @@ TEST_F(HostReservationParserTest, options4) {
            "\"csv-format\": true,"
            "\"space\": \"dhcp4\","
            "\"data\": \"172.16.15.23\","
-           "\"always-send\": false"
+           "\"always-send\": false,"
+           "\"never-send\": false"
         "},"
         "{"
            "\"name\": \"default-ip-ttl\","
@@ -1091,12 +1092,14 @@ TEST_F(HostReservationParserTest, options4) {
     option->set("space", Element::create(std::string(DHCP4_OPTION_SPACE)));
     option->set("csv-format", Element::create(true));
     option->set("always-send", Element::create(false));
+    option->set("never-send", Element::create(false));
     option = config_element->get("option-data")->getNonConst(1);
     option = config_element->get("option-data")->getNonConst(2);
     option->set("code", Element::create(DHO_DEFAULT_IP_TTL));
     option->set("space", Element::create(std::string(DHCP4_OPTION_SPACE)));
     option->set("csv-format", Element::create(true));
     option->set("always-send", Element::create(false));
+    option->set("never-send", Element::create(false));
     ElementPtr expected = Element::createList();
     expected->add(config_element);
 
@@ -1130,7 +1133,8 @@ TEST_F(HostReservationParserTest, options6) {
            "\"csv-format\": true,"
            "\"space\": \"dhcp6\","
            "\"data\": \"2001:db8:1::1204\","
-           "\"always-send\": true"
+           "\"always-send\": true,"
+           "\"never-send\": true"
         "},"
         "{"
            "\"name\": \"preference\","
@@ -1184,12 +1188,14 @@ TEST_F(HostReservationParserTest, options6) {
     option->set("space", Element::create(std::string(DHCP6_OPTION_SPACE)));
     option->set("csv-format", Element::create(true));
     option->set("always-send", Element::create(false));
+    option->set("never-send", Element::create(false));
     option = config_element->get("option-data")->getNonConst(1);
     option = config_element->get("option-data")->getNonConst(2);
     option->set("code", Element::create(D6O_PREFERENCE));
     option->set("space", Element::create(std::string(DHCP6_OPTION_SPACE)));
     option->set("csv-format", Element::create(true));
     option->set("always-send", Element::create(false));
+    option->set("never-send", Element::create(false));
     config = prettyPrint(config_element);
     boost::algorithm::to_lower(config);
 
index a7ee02db918402a4acaf5142b326b78cd7a377d5..5cf3c76745ae6b823478f9a3b7d8d765c2d06d76 100644 (file)
@@ -895,14 +895,15 @@ TEST_F(HostTest, addOptions4) {
     // Differentiate options by their codes (100-109)
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(host.getCfgOption4()->add(option, false, DHCP4_OPTION_SPACE));
+        ASSERT_NO_THROW(host.getCfgOption4()->add(option, false, false,
+                                                  DHCP4_OPTION_SPACE));
     }
 
     // Add 7 options to another option space. The option codes partially overlap
     // with option codes that we have added to dhcp4 option space.
     for (uint16_t code = 105; code < 112; ++code) {
         OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(host.getCfgOption4()->add(option, false, "isc"));
+        ASSERT_NO_THROW(host.getCfgOption4()->add(option, false, false, "isc"));
     }
 
     // Get options from the Subnet and check if all 10 are there.
@@ -959,14 +960,15 @@ TEST_F(HostTest, addOptions6) {
     // Differentiate options by their codes (100-109)
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(host.getCfgOption6()->add(option, false, DHCP6_OPTION_SPACE));
+        ASSERT_NO_THROW(host.getCfgOption6()->add(option, false, false,
+                                                  DHCP6_OPTION_SPACE));
     }
 
     // Add 7 options to another option space. The option codes partially overlap
     // with option codes that we have added to dhcp6 option space.
     for (uint16_t code = 105; code < 112; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(host.getCfgOption6()->add(option, false, "isc"));
+        ASSERT_NO_THROW(host.getCfgOption6()->add(option, false, false, "isc"));
     }
 
     // Get options from the Subnet and check if all 10 are there.
index 00d7819712a979003245f81073ceed2e060f76f4..3b532674c46d743509ba0b4b70e01c935789f135 100644 (file)
@@ -159,14 +159,15 @@ TEST(Pool4Test, addOptions) {
     // Differentiate options by their codes (100-109)
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "dhcp4"));
+        ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, false,
+                                                  "dhcp4"));
     }
 
     // Add 7 options to another option space. The option codes partially overlap
     // with option codes that we have added to dhcp4 option space.
     for (uint16_t code = 105; code < 112; ++code) {
         OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "isc"));
+        ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, false, "isc"));
     }
 
     // Get options from the pool and check if all 10 are there.
@@ -583,14 +584,15 @@ TEST(Pool6Test, addOptions) {
     // Differentiate options by their codes (100-109)
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "dhcp6"));
+        ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, false,
+                                                  "dhcp6"));
     }
 
     // Add 7 options to another option space. The option codes partially overlap
     // with option codes that we have added to dhcp6 option space.
     for (uint16_t code = 105; code < 112; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "isc"));
+        ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, false, "isc"));
     }
 
     // Get options from the pool and check if all 10 are there.
index 4b21f27383a3849466908f6579385924e78285f3..3935cdc8dc97c75859977b5f9428b87a4964f7ca 100644 (file)
@@ -385,7 +385,7 @@ TEST_F(SrvConfigTest, copy) {
 
     // Add an option.
     OptionPtr option(new Option(Option::V6, 1000, OptionBuffer(10, 0xFF)));
-    conf1.getCfgOption()->add(option, true, DHCP6_OPTION_SPACE);
+    conf1.getCfgOption()->add(option, true, false, DHCP6_OPTION_SPACE);
 
     // Add a class dictionary
     conf1.setClientClassDictionary(ref_dictionary_);
@@ -458,12 +458,12 @@ TEST_F(SrvConfigTest, equality) {
 
     // Differ by option data.
     OptionPtr option(new Option(Option::V6, 1000, OptionBuffer(1, 0xFF)));
-    conf1.getCfgOption()->add(option, false, "isc");
+    conf1.getCfgOption()->add(option, false, false, "isc");
 
     EXPECT_FALSE(conf1 == conf2);
     EXPECT_TRUE(conf1 != conf2);
 
-    conf2.getCfgOption()->add(option, false, "isc");
+    conf2.getCfgOption()->add(option, false, false, "isc");
 
     EXPECT_TRUE(conf1 == conf2);
     EXPECT_FALSE(conf1 != conf2);
index dfebc9e250e0d87e887074ef6696bd898fd6e210..58da38f59b94a482f0ee05940263f9a0f5dbb67c 100644 (file)
@@ -585,7 +585,8 @@ TEST(Subnet4Test, addInvalidOption) {
     // should result in exception.
     OptionPtr option2;
     ASSERT_FALSE(option2);
-    EXPECT_THROW(subnet->getCfgOption()->add(option2, false, DHCP4_OPTION_SPACE),
+    EXPECT_THROW(subnet->getCfgOption()->add(option2, false, false,
+                                             DHCP4_OPTION_SPACE),
                  isc::BadValue);
 }
 
@@ -680,8 +681,7 @@ TEST(Subnet4Test, parsePrefix) {
 
     // No slash sign.
     EXPECT_THROW(Subnet4::parsePrefix("10.0.0.1"), BadValue);
-
-    // IPv6 is not allowed here.
+   // IPv6 is not allowed here.
     EXPECT_THROW(Subnet4::parsePrefix("3000::/24"), BadValue);
 }
 
@@ -752,7 +752,7 @@ TEST(Subnet4Test, getServerId) {
     option_server_id->writeAddress(IOAddress("1.2.3.4"));
 
     CfgOptionPtr cfg_option = subnet.getCfgOption();
-    cfg_option->add(option_server_id, false, DHCP4_OPTION_SPACE);
+    cfg_option->add(option_server_id, false, false, DHCP4_OPTION_SPACE);
 
     // Verify that the server identifier returned by the Subnet4 object is
     // correct.
@@ -1312,14 +1312,16 @@ TEST(Subnet6Test, addOptions) {
     // Differentiate options by their codes (100-109)
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, DHCP6_OPTION_SPACE));
+        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, false,
+                                                    DHCP6_OPTION_SPACE));
     }
 
     // Add 7 options to another option space. The option codes partially overlap
     // with option codes that we have added to dhcp6 option space.
     for (uint16_t code = 105; code < 112; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, "isc"));
+        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, false,
+                                                    "isc"));
     }
 
     // Get options from the Subnet and check if all 10 are there.
@@ -1364,7 +1366,8 @@ TEST(Subnet6Test, addNonUniqueOptions) {
         // In the inner loop we create options with unique codes (100-109).
         for (uint16_t code = 100; code < 110; ++code) {
             OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-            ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, DHCP6_OPTION_SPACE));
+            ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, false,
+                                                        DHCP6_OPTION_SPACE));
         }
     }
 
@@ -1412,7 +1415,9 @@ TEST(Subnet6Test, addPersistentOption) {
         // and options with these codes will be flagged non-persistent.
         // Options with other codes will be flagged persistent.
         bool persistent = (code % 3) ? true : false;
-        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, persistent, DHCP6_OPTION_SPACE));
+        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, persistent,
+                                                    false,
+                                                    DHCP6_OPTION_SPACE));
     }
 
     // Get added options from the subnet.
@@ -1439,7 +1444,8 @@ TEST(Subnet6Test, getOptions) {
     // Add 10 options to a "dhcp6" option space in the subnet.
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, DHCP6_OPTION_SPACE));
+        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, false,
+                                                    DHCP6_OPTION_SPACE));
     }
 
     // Check that we can get each added option descriptor using
@@ -1466,14 +1472,16 @@ TEST(Subnet6Test, addVendorOption) {
     // Differentiate options by their codes (100-109)
     for (uint16_t code = 100; code < 110; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, "vendor-12345678"));
+        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, false,
+                                                    "vendor-12345678"));
     }
 
     // Add 7 options to another option space. The option codes partially overlap
     // with option codes that we have added to dhcp6 option space.
     for (uint16_t code = 105; code < 112; ++code) {
         OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
-        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, "vendor-87654321"));
+        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, false,
+                                                    "vendor-87654321"));
     }
 
     // Get options from the Subnet and check if all 10 are there.
index 344d2151e72c06cc570e6fc942e8a38d92c86dcd..c6c679637edcc3d9ecbff43227c148a7c395113f 100644 (file)
@@ -33,15 +33,17 @@ GenericBackendTest::~GenericBackendTest() {
 OptionDescriptor
 GenericBackendTest::createEmptyOption(const Option::Universe& universe,
                                       const uint16_t option_type,
-                                      const bool persist) const {
+                                      const bool persist,
+                                      const bool cancel) const {
     OptionPtr option(new Option(universe, option_type));
-    OptionDescriptor desc(option, persist);
+    OptionDescriptor desc(option, persist, cancel);
     return (desc);
 }
 
 OptionDescriptor
 GenericBackendTest::createVendorOption(const Option::Universe& universe,
                                        const bool persist,
+                                       const bool cancel,
                                        const bool formatted,
                                        const uint32_t vendor_id) const {
     OptionVendorPtr option(new OptionVendor(universe, vendor_id));
@@ -53,7 +55,7 @@ GenericBackendTest::createVendorOption(const Option::Universe& universe,
         s << vendor_id;
     }
 
-    OptionDescriptor desc(option, persist, s.str());
+    OptionDescriptor desc(option, persist, cancel, s.str());
     return (desc);
 }
 
@@ -102,6 +104,7 @@ GenericBackendTest::testOptionsEquivalent(const OptionDescriptor& ref_option,
     // option when an option definition is available.
     EXPECT_EQ(ref_option.formatted_value_, tested_option.formatted_value_);
     EXPECT_EQ(ref_option.persistent_, tested_option.persistent_);
+    EXPECT_EQ(ref_option.cancelled_, tested_option.cancelled_);
     EXPECT_EQ(ref_option.space_name_, tested_option.space_name_);
 }
 
index f45ba3dc70a7bb6da44f95f6824adbc194cc3556..44fe21ed815b94adcf1c3062ee28799e3d0a6a35 100644 (file)
@@ -53,11 +53,14 @@ public:
     /// @param option_type Option type.
     /// @param persist A boolean flag indicating if the option is always
     /// returned to the client or only when requested.
+    /// @param cancel A boolean flag indicating if the option must never
+    /// be returned to the client,
     ///
     /// @return Descriptor holding an empty option.
     OptionDescriptor createEmptyOption(const Option::Universe& universe,
                                        const uint16_t option_type,
-                                       const bool persist) const;
+                                       const bool persist,
+                                       const bool cancel) const;
 
     /// @brief Creates an instance of the option for which it is possible to
     /// specify universe, option type, persistence flag  and value in
@@ -71,6 +74,8 @@ public:
     /// @param option_type Option type.
     /// @param persist A boolean flag indicating if the option is always
     /// returned to the client or only when requested.
+    /// @param cancel A boolean flag indicating if the option must never
+    /// be returned to the client,
     /// @param formatted A boolean value selecting if the formatted option
     /// value should be used (if true), or binary value (if false).
     /// @param value Option value to be assigned to the option.
@@ -82,6 +87,7 @@ public:
     OptionDescriptor createOption(const Option::Universe& universe,
                                   const uint16_t option_type,
                                   const bool persist,
+                                  const bool cancel,
                                   const bool formatted,
                                   const DataType& value) const {
         boost::shared_ptr<OptionType> option(new OptionType(universe, option_type,
@@ -92,7 +98,7 @@ public:
             // textual format.
             s << value;
         }
-        OptionDescriptor desc(option, persist, s.str());
+        OptionDescriptor desc(option, persist, cancel, s.str());
         return (desc);
     }
 
@@ -106,6 +112,8 @@ public:
     /// @param option_type Option type.
     /// @param persist A boolean flag indicating if the option is always
     /// returned to the client or only when requested.
+    /// @param cancel A boolean flag indicating if the option must never
+    /// be returned to the client,
     /// @param formatted A boolean value selecting if the formatted option
     /// value should be used (if true), or binary value (if false).
     /// @param value Option value to be assigned to the option.
@@ -116,6 +124,7 @@ public:
     template<typename OptionType, typename DataType>
     OptionDescriptor createOption(const uint16_t option_type,
                                   const bool persist,
+                                  const bool cancel,
                                   const bool formatted,
                                   const DataType& value) const {
         boost::shared_ptr<OptionType> option(new OptionType(option_type, value));
@@ -127,7 +136,7 @@ public:
             s << value;
         }
 
-        OptionDescriptor desc(option, persist, s.str());
+        OptionDescriptor desc(option, persist, cancel, s.str());
         return (desc);
     }
 
@@ -136,6 +145,8 @@ public:
     /// @param option_type Option type.
     /// @param persist A boolean flag indicating if the option is always
     /// returned to the client or only when requested.
+    /// @param cancel A boolean flag indicating if the option must never
+    /// be returned to the client,
     /// @param formatted A boolean value selecting if the formatted option
     /// value should be used (if true), or binary value (if false).
     /// @param address1 First address to be included. If address is empty, it is
@@ -151,6 +162,7 @@ public:
     OptionDescriptor
     createAddressOption(const uint16_t option_type,
                         const bool persist,
+                        const bool cancel,
                         const bool formatted,
                         const std::string& address1 = "",
                         const std::string& address2 = "",
@@ -187,7 +199,7 @@ public:
 
         boost::shared_ptr<OptionType> option(new OptionType(option_type,
                                                             addresses));
-        OptionDescriptor desc(option, persist, s.str());
+        OptionDescriptor desc(option, persist, cancel, s.str());
         return (desc);
     }
 
@@ -196,6 +208,8 @@ public:
     /// @param universe V4 or V6.
     /// @param persist A boolean flag indicating if the option is always
     /// returned to the client or only when requested.
+    /// @param cancel A boolean flag indicating if the option must never
+    /// be returned to the client,
     /// @param formatted A boolean value selecting if the formatted option
     /// value should be used (if true), or binary value (if false).
     /// @param vendor_id Vendor identifier.
@@ -203,6 +217,7 @@ public:
     /// @return Descriptor holding an instance of the option created.
     OptionDescriptor createVendorOption(const Option::Universe& universe,
                                         const bool persist,
+                                        const bool cancel,
                                         const bool formatted,
                                         const uint32_t vendor_id) const;
 
@@ -349,4 +364,3 @@ public:
 } // end of namespace isc
 
 #endif
-
index 18dde4ae885709eb8e1ed532f794ee401a55b69f..990178604646b2946527b0b55861afd3a76c0c61 100644 (file)
@@ -137,14 +137,17 @@ GenericConfigBackendDHCPv4Test::initTestSubnets() {
     // 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_[1]->option_,
                                 test_options_[1]->persistent_,
+                                test_options_[1]->cancelled_,
                                 test_options_[1]->space_name_);
 
     subnet->getCfgOption()->add(test_options_[2]->option_,
                                 test_options_[2]->persistent_,
+                                test_options_[2]->cancelled_,
                                 test_options_[2]->space_name_);
 
     test_subnets_.push_back(subnet);
@@ -161,10 +164,12 @@ GenericConfigBackendDHCPv4Test::initTestSubnets() {
 
     pool1->getCfgOption()->add(test_options_[3]->option_,
                                test_options_[3]->persistent_,
+                               test_options_[3]->cancelled_,
                                test_options_[3]->space_name_);
 
     pool1->getCfgOption()->add(test_options_[4]->option_,
                                test_options_[4]->persistent_,
+                               test_options_[4]->cancelled_,
                                test_options_[4]->space_name_);
 
     pool2.reset(new Pool4(IOAddress("10.0.0.50"),
@@ -195,6 +200,7 @@ GenericConfigBackendDHCPv4Test::initTestSubnets() {
 
     subnet->getCfgOption()->add(test_options_[0]->option_,
                                 test_options_[0]->persistent_,
+                                test_options_[0]->cancelled_,
                                 test_options_[0]->space_name_);
 
     test_subnets_.push_back(subnet);
@@ -237,14 +243,17 @@ GenericConfigBackendDHCPv4Test::initTestSharedNetworks() {
     // Add several options to the shared network.
     shared_network->getCfgOption()->add(test_options_[2]->option_,
                                         test_options_[2]->persistent_,
+                                        test_options_[2]->cancelled_,
                                         test_options_[2]->space_name_);
 
     shared_network->getCfgOption()->add(test_options_[3]->option_,
                                         test_options_[3]->persistent_,
+                                        test_options_[3]->cancelled_,
                                         test_options_[3]->space_name_);
 
     shared_network->getCfgOption()->add(test_options_[4]->option_,
                                         test_options_[4]->persistent_,
+                                        test_options_[4]->cancelled_,
                                         test_options_[4]->space_name_);
 
     test_networks_.push_back(shared_network);
@@ -270,6 +279,7 @@ GenericConfigBackendDHCPv4Test::initTestSharedNetworks() {
 
     shared_network->getCfgOption()->add(test_options_[0]->option_,
                                         test_options_[0]->persistent_,
+                                        test_options_[0]->cancelled_,
                                         test_options_[0]->space_name_);
     test_networks_.push_back(shared_network);
 
@@ -315,30 +325,30 @@ GenericConfigBackendDHCPv4Test::initTestOptions() {
 
     OptionDescriptor desc =
         createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
-                                   true, false, "my-boot-file");
+                                   true, false, false, "my-boot-file");
     desc.space_name_ = DHCP4_OPTION_SPACE;
     desc.setContext(user_context);
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
     desc = createOption<OptionUint8>(Option::V4, DHO_DEFAULT_IP_TTL,
-                                     false, true, 64);
+                                     false, true, true, 64);
     desc.space_name_ = DHCP4_OPTION_SPACE;
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
-    desc = createOption<OptionUint32>(Option::V4, 1, false, false, 312131),
+    desc = createOption<OptionUint32>(Option::V4, 1, false, false, false, 312131),
     desc.space_name_ = "vendor-encapsulated-options";
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
-    desc = createAddressOption<Option4AddrLst>(254, true, true,
+    desc = createAddressOption<Option4AddrLst>(254, true, true, true,
                                                "192.0.2.3");
     desc.space_name_ = DHCP4_OPTION_SPACE;
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
-    desc = createEmptyOption(Option::V4, 1, true);
+    desc = createEmptyOption(Option::V4, 1, true, true);
     desc.space_name_ = "isc";
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
-    desc = createAddressOption<Option4AddrLst>(2, false, true,
+    desc = createAddressOption<Option4AddrLst>(2, false, false, true,
                                                "10.0.0.5",
                                                "10.0.0.3",
                                                "10.0.3.4");
@@ -346,13 +356,13 @@ GenericConfigBackendDHCPv4Test::initTestOptions() {
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
     desc = createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
-                                      true, false, "my-boot-file-2");
+                                      true, false, false, "my-boot-file-2");
     desc.space_name_ = DHCP4_OPTION_SPACE;
     desc.setContext(user_context);
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
     desc = createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
-                                      true, false, "my-boot-file-3");
+                                      true, true, false, "my-boot-file-3");
     desc.space_name_ = DHCP4_OPTION_SPACE;
     desc.setContext(user_context);
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
@@ -3207,6 +3217,7 @@ GenericConfigBackendDHCPv4Test::createUpdateDeleteOption4Test() {
 
     // Modify option and update it in the database.
     opt_boot_file_name->persistent_ = !opt_boot_file_name->persistent_;
+    opt_boot_file_name->cancelled_ = !opt_boot_file_name->cancelled_;
     cbptr_->createUpdateOption4(ServerSelector::ALL(),
                                 opt_boot_file_name);
 
@@ -3584,6 +3595,7 @@ GenericConfigBackendDHCPv4Test::createUpdateDeleteSubnetOption4Test() {
     ASSERT_EQ(3, countRows("dhcp4_options"));
 
     opt_boot_file_name->persistent_ = !opt_boot_file_name->persistent_;
+    opt_boot_file_name->cancelled_ = !opt_boot_file_name->cancelled_;
     cbptr_->createUpdateOption4(ServerSelector::ANY(), subnet->getID(),
                                 opt_boot_file_name);
 
@@ -3692,6 +3704,7 @@ GenericConfigBackendDHCPv4Test::createUpdateDeletePoolOption4Test() {
 
     // Modify the option and update it in the database.
     opt_boot_file_name->persistent_ = !opt_boot_file_name->persistent_;
+    opt_boot_file_name->cancelled_ = !opt_boot_file_name->cancelled_;
     cbptr_->createUpdateOption4(ServerSelector::ANY(),
                                 pool->getFirstAddress(),
                                 pool->getLastAddress(),
@@ -3817,6 +3830,7 @@ GenericConfigBackendDHCPv4Test::createUpdateDeleteSharedNetworkOption4Test() {
     ASSERT_EQ(1, countRows("dhcp4_options"));
 
     opt_boot_file_name->persistent_ = !opt_boot_file_name->persistent_;
+    opt_boot_file_name->cancelled_ = !opt_boot_file_name->cancelled_;
     cbptr_->createUpdateOption4(ServerSelector::ANY(),
                                 shared_network->getName(),
                                 opt_boot_file_name);
@@ -4071,9 +4085,11 @@ GenericConfigBackendDHCPv4Test::getClientClass4Test() {
     auto class1 = test_client_classes_[0];
     ASSERT_NO_THROW_LOG(class1->getCfgOption()->add(test_options_[0]->option_,
                                                     test_options_[0]->persistent_,
+                                                    test_options_[0]->cancelled_,
                                                     test_options_[0]->space_name_));
     ASSERT_NO_THROW_LOG(class1->getCfgOption()->add(test_options_[1]->option_,
                                                     test_options_[1]->persistent_,
+                                                    test_options_[1]->cancelled_,
                                                     test_options_[1]->space_name_));
     ASSERT_NO_THROW_LOG(cbptr_->createUpdateClientClass4(ServerSelector::ALL(), class1, ""));
 
@@ -4142,9 +4158,11 @@ GenericConfigBackendDHCPv4Test::createUpdateClientClass4OptionsTest() {
     auto class1 = test_client_classes_[0];
     ASSERT_NO_THROW_LOG(class1->getCfgOption()->add(test_options_[0]->option_,
                                                     test_options_[0]->persistent_,
+                                                    test_options_[0]->cancelled_,
                                                     test_options_[0]->space_name_));
     ASSERT_NO_THROW_LOG(class1->getCfgOption()->add(test_options_[1]->option_,
                                                     test_options_[1]->persistent_,
+                                                    test_options_[1]->cancelled_,
                                                     test_options_[1]->space_name_));
     auto cfg_option_def = boost::make_shared<CfgOptionDef>();
     class1->setCfgOptionDef(cfg_option_def);
index 7322d52d7ae50f24676414ee55680ba743a9bca1..0574dcaed8d9a5d40b1079bc1337d750a40a16bd 100644 (file)
@@ -143,14 +143,17 @@ GenericConfigBackendDHCPv6Test::initTestSubnets() {
     // 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_[1]->option_,
                                 test_options_[1]->persistent_,
+                                test_options_[1]->cancelled_,
                                 test_options_[1]->space_name_);
 
     subnet->getCfgOption()->add(test_options_[2]->option_,
                                 test_options_[2]->persistent_,
+                                test_options_[2]->cancelled_,
                                 test_options_[2]->space_name_);
 
     test_subnets_.push_back(subnet);
@@ -168,10 +171,12 @@ GenericConfigBackendDHCPv6Test::initTestSubnets() {
 
     pool1->getCfgOption()->add(test_options_[3]->option_,
                                test_options_[3]->persistent_,
+                               test_options_[3]->cancelled_,
                                test_options_[3]->space_name_);
 
     pool1->getCfgOption()->add(test_options_[4]->option_,
                                test_options_[4]->persistent_,
+                               test_options_[4]->cancelled_,
                                test_options_[4]->space_name_);
 
     pool2.reset(new Pool6(Lease::TYPE_NA,
@@ -191,10 +196,12 @@ GenericConfigBackendDHCPv6Test::initTestSubnets() {
 
     pdpool1->getCfgOption()->add(test_options_[3]->option_,
                                  test_options_[3]->persistent_,
+                                 test_options_[3]->cancelled_,
                                  test_options_[3]->space_name_);
 
     pdpool1->getCfgOption()->add(test_options_[4]->option_,
                                  test_options_[4]->persistent_,
+                                 test_options_[4]->cancelled_,
                                  test_options_[4]->space_name_);
 
     // Create the prefix delegation pool with an excluded prefix.
@@ -228,6 +235,7 @@ GenericConfigBackendDHCPv6Test::initTestSubnets() {
 
     subnet->getCfgOption()->add(test_options_[0]->option_,
                                 test_options_[0]->persistent_,
+                                test_options_[0]->cancelled_,
                                 test_options_[0]->space_name_);
 
     test_subnets_.push_back(subnet);
@@ -272,14 +280,17 @@ GenericConfigBackendDHCPv6Test::initTestSharedNetworks() {
     // Add several options to the shared network.
     shared_network->getCfgOption()->add(test_options_[2]->option_,
                                         test_options_[2]->persistent_,
+                                        test_options_[2]->cancelled_,
                                         test_options_[2]->space_name_);
 
     shared_network->getCfgOption()->add(test_options_[3]->option_,
                                         test_options_[3]->persistent_,
+                                        test_options_[3]->cancelled_,
                                         test_options_[3]->space_name_);
 
     shared_network->getCfgOption()->add(test_options_[4]->option_,
                                         test_options_[4]->persistent_,
+                                        test_options_[4]->cancelled_,
                                         test_options_[4]->space_name_);
 
     test_networks_.push_back(shared_network);
@@ -307,6 +318,7 @@ GenericConfigBackendDHCPv6Test::initTestSharedNetworks() {
 
     shared_network->getCfgOption()->add(test_options_[0]->option_,
                                         test_options_[0]->persistent_,
+                                        test_options_[0]->cancelled_,
                                         test_options_[0]->space_name_);
     test_networks_.push_back(shared_network);
 
@@ -352,30 +364,30 @@ GenericConfigBackendDHCPv6Test::initTestOptions() {
 
     OptionDescriptor desc =
         createOption<OptionString>(Option::V6, D6O_NEW_POSIX_TIMEZONE,
-                                   true, false, "my-timezone");
+                                   true, false, false, "my-timezone");
     desc.space_name_ = DHCP6_OPTION_SPACE;
     desc.setContext(user_context);
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
     desc = createOption<OptionUint8>(Option::V6, D6O_PREFERENCE,
-                                     false, true, 64);
+                                     false, false, true, 64);
     desc.space_name_ = DHCP6_OPTION_SPACE;
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
-    desc = createOption<OptionUint32>(Option::V6, 1, false, false, 312131),
+    desc = createOption<OptionUint32>(Option::V6, 1, false, false, false, 312131),
     desc.space_name_ = "vendor-encapsulated-options";
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
-    desc = createAddressOption<Option6AddrLst>(1254, true, true,
+    desc = createAddressOption<Option6AddrLst>(1254, true, true, true,
                                                "2001:db8::3");
     desc.space_name_ = DHCP6_OPTION_SPACE;
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
-    desc = createEmptyOption(Option::V6, 1, true);
+    desc = createEmptyOption(Option::V6, 1, true, false);
     desc.space_name_ = "isc";
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
-    desc = createAddressOption<Option6AddrLst>(2, false, true,
+    desc = createAddressOption<Option6AddrLst>(2, false, false, true,
                                                "2001:db8:1::5",
                                                "2001:db8:1::3",
                                                "2001:db8:3::4");
@@ -383,13 +395,13 @@ GenericConfigBackendDHCPv6Test::initTestOptions() {
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
     desc = createOption<OptionString>(Option::V6, D6O_NEW_POSIX_TIMEZONE,
-                                      true, false, "my-timezone-2");
+                                      true, false, false, "my-timezone-2");
     desc.space_name_ = DHCP6_OPTION_SPACE;
     desc.setContext(user_context);
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
 
     desc = createOption<OptionString>(Option::V6, D6O_NEW_POSIX_TIMEZONE,
-                                      true, false, "my-timezone-3");
+                                      true, true, false, "my-timezone-3");
     desc.space_name_ = DHCP6_OPTION_SPACE;
     desc.setContext(user_context);
     test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
@@ -3236,6 +3248,7 @@ GenericConfigBackendDHCPv6Test::createUpdateDeleteOption6Test() {
 
     // Modify option and update it in the database.
     opt_posix_timezone->persistent_ = !opt_posix_timezone->persistent_;
+    opt_posix_timezone->cancelled_ = !opt_posix_timezone->cancelled_;
     cbptr_->createUpdateOption6(ServerSelector::ALL(),
                                 opt_posix_timezone);
 
@@ -3613,6 +3626,7 @@ GenericConfigBackendDHCPv6Test::createUpdateDeleteSubnetOption6Test() {
     ASSERT_EQ(5, countRows("dhcp6_options"));
 
     opt_posix_timezone->persistent_ = !opt_posix_timezone->persistent_;
+    opt_posix_timezone->cancelled_ = !opt_posix_timezone->cancelled_;
     cbptr_->createUpdateOption6(ServerSelector::ANY(), subnet->getID(),
                                 opt_posix_timezone);
 
@@ -3721,6 +3735,7 @@ GenericConfigBackendDHCPv6Test::createUpdateDeletePoolOption6Test() {
 
     // Modify the option and update it in the database.
     opt_posix_timezone->persistent_ = !opt_posix_timezone->persistent_;
+    opt_posix_timezone->cancelled_ = !opt_posix_timezone->cancelled_;
     cbptr_->createUpdateOption6(ServerSelector::ANY(),
                                 pool->getFirstAddress(),
                                 pool->getLastAddress(),
@@ -3851,6 +3866,7 @@ GenericConfigBackendDHCPv6Test::createUpdateDeletePdPoolOption6Test() {
 
     // Modify the option and update it in the database.
     opt_posix_timezone->persistent_ = !opt_posix_timezone->persistent_;
+    opt_posix_timezone->cancelled_ = !opt_posix_timezone->cancelled_;
     cbptr_->createUpdateOption6(ServerSelector::ANY(),
                                 pd_pool->getFirstAddress(),
                                 static_cast<uint8_t>(pd_pool_len),
@@ -3976,6 +3992,7 @@ GenericConfigBackendDHCPv6Test::createUpdateDeleteSharedNetworkOption6Test() {
     ASSERT_EQ(1, countRows("dhcp6_options"));
 
     opt_posix_timezone->persistent_ = !opt_posix_timezone->persistent_;
+    opt_posix_timezone->cancelled_ = !opt_posix_timezone->cancelled_;
     cbptr_->createUpdateOption6(ServerSelector::ANY(),
                                 shared_network->getName(),
                                 opt_posix_timezone);
@@ -4230,9 +4247,11 @@ GenericConfigBackendDHCPv6Test::getClientClass6Test() {
     auto class1 = test_client_classes_[0];
     ASSERT_NO_THROW_LOG(class1->getCfgOption()->add(test_options_[0]->option_,
                                                     test_options_[0]->persistent_,
+                                                    test_options_[0]->cancelled_,
                                                     test_options_[0]->space_name_));
     ASSERT_NO_THROW_LOG(class1->getCfgOption()->add(test_options_[1]->option_,
                                                     test_options_[1]->persistent_,
+                                                    test_options_[1]->cancelled_,
                                                     test_options_[1]->space_name_));
     ASSERT_NO_THROW_LOG(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
 
@@ -4298,9 +4317,11 @@ GenericConfigBackendDHCPv6Test::createUpdateClientClass6OptionsTest() {
     auto class1 = test_client_classes_[0];
     ASSERT_NO_THROW_LOG(class1->getCfgOption()->add(test_options_[0]->option_,
                                                     test_options_[0]->persistent_,
+                                                    test_options_[0]->cancelled_,
                                                     test_options_[0]->space_name_));
     ASSERT_NO_THROW_LOG(class1->getCfgOption()->add(test_options_[1]->option_,
                                                     test_options_[1]->persistent_,
+                                                    test_options_[1]->cancelled_,
                                                     test_options_[1]->space_name_));
     auto cfg_option_def = boost::make_shared<CfgOptionDef>();
     class1->setCfgOptionDef(cfg_option_def);
index d4c211cea7dc834f7557fb419f07111a7781d8f4..53dc5cb4573009e04d5ef87e773bab356cc99d93 100644 (file)
@@ -119,19 +119,23 @@ GenericHostDataSourceTest::addTestOptions(const HostPtr& host,
         CfgOptionPtr opts = host->getCfgOption4();
         OptionDescriptor desc =
             createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
-                                       true, formatted, "my-boot-file");
+                                       true, false, formatted, "my-boot-file");
         desc.setContext(user_context);
         opts->add(desc, DHCP4_OPTION_SPACE);
         opts->add(createOption<OptionUint8>(Option::V4, DHO_DEFAULT_IP_TTL,
-                                            false, formatted, 64),
+                                            false, false, formatted, 64),
                   DHCP4_OPTION_SPACE);
-        opts->add(createOption<OptionUint32>(Option::V4, 1, false, formatted, 312131),
+        opts->add(createOption<OptionUint32>(Option::V4, 1, false, false,
+                                             formatted, 312131),
                   "vendor-encapsulated-options");
-        opts->add(createAddressOption<Option4AddrLst>(254, false, formatted,
-                                                      "192.0.2.3"), DHCP4_OPTION_SPACE);
-        opts->add(createEmptyOption(Option::V4, 1, true), "isc");
-        opts->add(createAddressOption<Option4AddrLst>(2, false, formatted, "10.0.0.5",
-                                                      "10.0.0.3", "10.0.3.4"), "isc");
+        opts->add(createAddressOption<Option4AddrLst>(254, false, false,
+                                                      formatted, "192.0.2.3"),
+                  DHCP4_OPTION_SPACE);
+        opts->add(createEmptyOption(Option::V4, 1, true, false), "isc");
+        opts->add(createAddressOption<Option4AddrLst>(2, false, false,
+                                                      formatted, "10.0.0.5",
+                                                      "10.0.0.3", "10.0.3.4"),
+                  "isc");
 
         // Add definitions for DHCPv4 non-standard options.
         defs.addItem(OptionDefinitionPtr(new OptionDefinition(
@@ -149,20 +153,22 @@ GenericHostDataSourceTest::addTestOptions(const HostPtr& host,
         CfgOptionPtr opts = host->getCfgOption6();
         OptionDescriptor desc =
             createOption<OptionString>(Option::V6, D6O_BOOTFILE_URL,
-                                       true, formatted, "my-boot-file");
+                                       true, false, formatted, "my-boot-file");
         desc.setContext(user_context);
         opts->add(desc, DHCP6_OPTION_SPACE);
         opts->add(createOption<OptionUint32>(Option::V6, D6O_INFORMATION_REFRESH_TIME,
-                                             false, formatted, 3600),
+                                             false, false, formatted, 3600),
                   DHCP6_OPTION_SPACE);
-        opts->add(createVendorOption(Option::V6, false, formatted, 2495),
+        opts->add(createVendorOption(Option::V6, false, false, formatted, 2495),
                   DHCP6_OPTION_SPACE);
-        opts->add(createAddressOption<Option6AddrLst>(1024, false, formatted,
-                                                      "2001:db8:1::1"),
+        opts->add(createAddressOption<Option6AddrLst>(1024, false, false,
+                                                      formatted, "2001:db8:1::1"),
                   DHCP6_OPTION_SPACE);
-        opts->add(createEmptyOption(Option::V6, 1, true), "isc2");
-        opts->add(createAddressOption<Option6AddrLst>(2, false, formatted, "3000::1",
-                                                      "3000::2", "3000::3"), "isc2");
+        opts->add(createEmptyOption(Option::V6, 1, true, false), "isc2");
+        opts->add(createAddressOption<Option6AddrLst>(2, false, false,
+                                                      formatted, "3000::1",
+                                                      "3000::2", "3000::3"),
+                  "isc2");
 
         // Add definitions for DHCPv6 non-standard options.
         defs.addItem(OptionDefinitionPtr(new OptionDefinition(
@@ -532,7 +538,7 @@ GenericHostDataSourceTest::testGetAllbyHostnameSubnet4() {
     CfgOptionPtr opts = host2->getCfgOption4();
     OptionDescriptor desc =
         createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
-                                   true, false, "my-boot-file");
+                                   true, false, false, "my-boot-file");
     opts->add(desc, DHCP4_OPTION_SPACE);
 
     HostPtr host3 = HostDataSourceUtils::initializeHost4("192.0.2.3", id);
@@ -615,7 +621,7 @@ GenericHostDataSourceTest::testGetAllbyHostnameSubnet6() {
     CfgOptionPtr opts = host2->getCfgOption6();
     OptionDescriptor desc =
         createOption<OptionString>(Option::V6, D6O_BOOTFILE_URL,
-                                   true, true, "my-boot-file");
+                                   true, false, true, "my-boot-file");
     opts->add(desc, DHCP6_OPTION_SPACE);
 
     HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8::3", id, false);
@@ -803,12 +809,12 @@ GenericHostDataSourceTest::testGetPageLimit4(const Host::IdentifierType& id) {
         CfgOptionPtr opts = host->getCfgOption4();
         OptionDescriptor desc =
             createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
-                                       true, false, "my-boot-file");
+                                       true, false, false, "my-boot-file");
         opts->add(desc, DHCP4_OPTION_SPACE);
         opts->add(createOption<OptionUint8>(Option::V4, DHO_DEFAULT_IP_TTL,
-                                            false, false, 64 + i),
+                                            false, true, false, 64 + i),
                   DHCP4_OPTION_SPACE);
-        opts->add(createEmptyOption(Option::V4, 1, true), "isc");
+        opts->add(createEmptyOption(Option::V4, 1, true, true), "isc");
 
         ASSERT_NO_THROW(hdsptr_->add(host));
     }
@@ -871,14 +877,14 @@ GenericHostDataSourceTest::testGetPageLimit6(const Host::IdentifierType& id) {
         CfgOptionPtr opts = host->getCfgOption6();
         OptionDescriptor desc =
             createOption<OptionString>(Option::V6, D6O_BOOTFILE_URL,
-                                       true, false, "my-boot-file");
+                                       true, false, false, "my-boot-file");
         opts->add(desc, DHCP6_OPTION_SPACE);
         opts->add(createOption<OptionUint32>(Option::V6,
                                              D6O_INFORMATION_REFRESH_TIME,
-                                             false, false, 3600 + i),
+                                             false, true, false, 3600 + i),
                   DHCP6_OPTION_SPACE);
         opts->add(createAddressOption<Option6AddrLst>(D6O_SIP_SERVERS_ADDR,
-                                                      false, false,
+                                                      false, false, false,
                                                       addr.toText()),
                   DHCP6_OPTION_SPACE);
 
index f7f38b9e94a0a80e858ac27325a4960ed4aaed50..b15034269e7f3a455fd17254aa096437188a48e3 100644 (file)
@@ -52,7 +52,7 @@ const int MLM_MYSQL_FETCH_FAILURE = 0;
 
 /// @name Current database schema version values.
 //@{
-const uint32_t MYSQL_SCHEMA_VERSION_MAJOR = 14;
+const uint32_t MYSQL_SCHEMA_VERSION_MAJOR = 15;
 const uint32_t MYSQL_SCHEMA_VERSION_MINOR = 0;
 
 //@}
index d73835c0a8ee50b651b7c5fcfa8db159e7d0e4a6..85430bb3ac44d29438915540cfc939503864a462 100644 (file)
@@ -18,7 +18,7 @@ namespace isc {
 namespace db {
 
 /// @brief Define the PostgreSQL backend version.
-const uint32_t PGSQL_SCHEMA_VERSION_MAJOR = 13;
+const uint32_t PGSQL_SCHEMA_VERSION_MAJOR = 14;
 const uint32_t PGSQL_SCHEMA_VERSION_MINOR = 0;
 
 // Maximum number of parameters that can be used a statement
index f580865d27e6f9dbed451f3184030dcf1bfb211f..82ea5233cb2aa40927064a241c329654f58c46c8 100644 (file)
@@ -77,7 +77,8 @@ const std::string subnetOptionsJson4 =
     "            \"space\": \"dns\",\n"
     "            \"csv-format\": false,\n"
     "            \"data\": \"12121212\",\n"
-    "            \"always-send\": false\n"
+    "            \"always-send\": false,\n"
+    "            \"never-send\": false\n"
     "          }\n"
     "        ],\n"
     "        \"pools\": [\n"
@@ -113,7 +114,8 @@ const std::string subnetOptionsJson6 =
     "                \"space\": \"dns\",\n"
     "                \"csv-format\": false,\n"
     "                \"data\": \"12121212\",\n"
-    "                \"always-send\": false\n"
+    "                \"always-send\": false,\n"
+    "                \"never-send\": false\n"
     "              }\n"
     "            ],\n"
     "            \"pool\": \"2001:db8::1:0/112\"\n"
index 9b415c7ff684ab93b94c0a7cbe5f95b5409c3daf..64611d767d571632287bc54c792e7c9a0c8a3353 100644 (file)
@@ -61,12 +61,14 @@ TEST_F(TranslatorOptionDataListTestv6, get) {
     const string& xoption = xpath + "/option-data[code='100'][space='dns']";
     const string& xformat = xoption + "/csv-format";
     const string& xdata = xoption + "/data";
-    const string& xsend = xoption + "/always-send";
+    const string& xalways = xoption + "/always-send";
+    const string& xnever = xoption + "/never-send";
     string const s_false("false");
     ASSERT_NO_THROW_LOG(sess_->setItem(xformat, s_false));
     string const s_data("12121212");
     ASSERT_NO_THROW_LOG(sess_->setItem(xdata, s_data));
-    ASSERT_NO_THROW_LOG(sess_->setItem(xsend, s_false));
+    ASSERT_NO_THROW_LOG(sess_->setItem(xalways, s_false));
+    ASSERT_NO_THROW_LOG(sess_->setItem(xnever, s_false));
     sess_->applyChanges();
 
     // Get the option data.
@@ -78,6 +80,7 @@ TEST_F(TranslatorOptionDataListTestv6, get) {
               " \"code\": 100,"
               " \"csv-format\": false,"
               " \"data\": \"12121212\","
+              " \"never-send\": false,"
               " \"space\": \"dns\""
               " }",
               option->str());
@@ -117,6 +120,7 @@ TEST_F(TranslatorOptionDataListTestv6, set) {
     option->set("csv-format", Element::create(false));
     option->set("data", Element::create("12121212"));
     option->set("always-send", Element::create(false));
+    option->set("never-send", Element::create(false));
     options->add(option);
     EXPECT_NO_THROW_LOG(translator_->setOptionDataList(xpath, options));
 
index c3bb0530c73c38b9099bf9ade36f9884297ef776..4446e263e0f34f91111c69b4a5ed1e41c766a65b 100644 (file)
@@ -423,6 +423,9 @@ const YRTree subnetOptionsTreeKeaDhcp4 = YangRepr::buildTreeFromVector({
     { "/kea-dhcp4-server:config/subnet4[id='111']/"
       "option-data[code='100'][space='dns']/always-send",
       "false", libyang::LeafBaseType::Bool, true },
+    { "/kea-dhcp4-server:config/subnet4[id='111']/"
+      "option-data[code='100'][space='dns']/never-send",
+      "false", libyang::LeafBaseType::Bool, true },
     { "/kea-dhcp4-server:config/subnet4[id='111']/"
       "pool[start-address='10.0.1.0'][end-address='10.0.1.255']",
       std::nullopt, libyang::LeafBaseType::Unknown, false },
@@ -504,6 +507,10 @@ const YRTree subnetOptionsTreeKeaDhcp6 = YangRepr::buildTreeFromVector({
       "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/"
       "option-data[code='100'][space='dns']/always-send",
       "false", libyang::LeafBaseType::Bool, true },
+    { "/kea-dhcp6-server:config/subnet6[id='111']/"
+      "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/"
+      "option-data[code='100'][space='dns']/never-send",
+      "false", libyang::LeafBaseType::Bool, true },
     { "/kea-dhcp6-server:config/subnet6[id='111']/subnet",
       "2001:db8::/48", libyang::LeafBaseType::String, true },
     { "/kea-dhcp6-server:config/expired-leases-processing",
index bc5df73c9ad1d38004f3b624892dad0efdd9be33..26a9c4f103580cc9047e6a2fe4297a725a48b3d2 100644 (file)
@@ -60,6 +60,7 @@ TranslatorOptionData::getOptionDataKea(DataNode const& data_node) {
     checkAndGetLeaf(result, data_node, "csv-format");
     checkAndGetLeaf(result, data_node, "data");
     checkAndGetLeaf(result, data_node, "name");
+    checkAndGetLeaf(result, data_node, "never-send");
 
     checkAndGetAndJsonifyLeaf(result, data_node, "user-context");
 
@@ -94,6 +95,7 @@ TranslatorOptionData::setOptionDataKea(string const& xpath,
     checkAndSetLeaf(elem, xpath, "csv-format", LeafBaseType::Bool);
     checkAndSetLeaf(elem, xpath, "data", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "name", LeafBaseType::String);
+    checkAndSetLeaf(elem, xpath, "never-send", LeafBaseType::Bool);
 
     checkAndSetUserContext(elem, xpath);
 }
index cd57b3661865c040c54d70203582960e18d0555b..3a53e1d7fcd545d4bb828fffb7bc8d5df19471f3 100644 (file)
@@ -23,6 +23,7 @@ namespace yang {
 ///     "csv-format": <csv format flag>,
 ///     "data": <value>,
 ///     "always-send": <always send flag>,
+///     "never-send": <never send flag>,
 ///     "user-context": { <json map> },
 ///     "comment": "<comment>"
 /// }
@@ -37,6 +38,7 @@ namespace yang {
 ///    +--rw data?           string
 ///    +--rw csv-format?     boolean
 ///    +--rw always-send?    boolean
+///    +--rw never-send?     boolean
 ///    +--rw user-context?   user-context
 /// @endcode
 ///
@@ -48,7 +50,8 @@ namespace yang {
 ///         "space": "dns",
 ///         "csv-format": false,
 ///         "data": "12121212",
-///         "always-send": false
+///         "always-send": false,
+///         "never-send": false
 ///     }
 /// ]
 /// @endcode
@@ -66,6 +69,8 @@ namespace yang {
 ///     option-data[code='100'][space='dns']/csv-format = false
 ///  /kea-dhcp6-server:config/
 ///     option-data[code='100'][space='dns']/always-send = false
+///  /kea-dhcp6-server:config/
+///     option-data[code='100'][space='dns']/never-send = false
 /// @endcode
 
 /// @brief A translator class for converting an option data between
index b28a400804cd8c9c1ad02b3fa6a20c3e02563d05..24227de48d833d66216be1ceff3c4b8eba2f687d 100644 (file)
@@ -22,9 +22,9 @@ static const std::unordered_map<std::string, std::string> YANG_REVISIONS = {
     { "ietf-dhcpv6-options", "2018-09-04" },
     { "ietf-dhcpv6-server", "2018-09-04" },
     { "kea-types", "2019-08-12" },
-    { "kea-dhcp-types", "2022-11-30" },
-    { "kea-dhcp4-server", "2022-11-30" },
-    { "kea-dhcp6-server", "2022-11-30" },
+    { "kea-dhcp-types", "2022-12-27" },
+    { "kea-dhcp4-server", "2022-12-27" },
+    { "kea-dhcp6-server", "2022-12-27" },
     { "kea-ctrl-agent", "2019-08-12" },
     { "kea-dhcp-ddns", "2022-07-27" }
 };  // YANG_REVISIONS
index 29ba228fafc3a0f3089bef8a0d5660b983c48186..a82867c915aac070abdcac5ad7ef12c7a1a302fe 100644 (file)
@@ -33,6 +33,7 @@ mysql_SCRIPTS += upgrade_010_to_011.sh
 mysql_SCRIPTS += upgrade_011_to_012.sh
 mysql_SCRIPTS += upgrade_012_to_013.sh
 mysql_SCRIPTS += upgrade_013_to_014.sh
+mysql_SCRIPTS += upgrade_014_to_015.sh
 mysql_SCRIPTS += wipe_data.sh
 
 DISTCLEANFILES = ${mysql_SCRIPTS}
index 9811e7da0b65bcdc19db677b152a6edae013a9ec..bb68eb8914b3dfaafc69bc88addde46688dc59a0 100644 (file)
@@ -5063,6 +5063,22 @@ UPDATE schema_version
 
 -- This line concludes the schema upgrade to version 14.
 
+-- This line starts the schema upgrade to version 15.
+
+-- Add cancelled (aka never-send) column to option tables.
+
+ALTER TABLE dhcp4_options
+    ADD COLUMN cancelled TINYINT(1) NOT NULL DEFAULT 0;
+
+ALTER TABLE dhcp6_options
+    ADD COLUMN cancelled TINYINT(1) NOT NULL DEFAULT 0;
+
+-- Update the schema version number.
+UPDATE schema_version
+    SET version = '15', minor = '0';
+
+-- This line concludes the schema upgrade to version 15.
+
 # Notes:
 #
 # Indexes
index f9c20961e453085144ab86b643d2a2f0d03b7cfe..cb55f3a805e270ebf91c713377204b1334ca7e04 100644 (file)
@@ -27,6 +27,7 @@ pgsql_SCRIPTS += upgrade_009_to_010.sh
 pgsql_SCRIPTS += upgrade_010_to_011.sh
 pgsql_SCRIPTS += upgrade_011_to_012.sh
 pgsql_SCRIPTS += upgrade_012_to_013.sh
+pgsql_SCRIPTS += upgrade_013_to_014.sh
 pgsql_SCRIPTS += wipe_data.sh
 
 DISTCLEANFILES = ${pgsql_SCRIPTS}
index f24e086a6ef70050e0ec73fb5ebbee45968ddb8d..37cb3824a59b8c938293871bffde3d1e92df8118 100644 (file)
@@ -5626,6 +5626,19 @@ UPDATE schema_version
 
 -- This line concludes the schema upgrade to version 13.
 
+-- This line starts the schema upgrade to version 14.
+
+-- Add cancelled (aka never-send) column to option tables.
+
+ALTER TABLE dhcp4_options ADD COLUMN cancelled BOOLEAN NOT NULL DEFAULT 'f';
+ALTER TABLE dhcp6_options ADD COLUMN cancelled BOOLEAN NOT NULL DEFAULT 'f';
+
+-- Update the schema version number.
+UPDATE schema_version
+    SET version = '14', minor = '0';
+
+-- This line concludes the schema upgrade to version 14.
+
 -- Commit the script transaction.
 COMMIT;