From: Francis Dupont Date: Mon, 6 Mar 2023 16:34:30 +0000 (+0100) Subject: [#719] Reapplied patch X-Git-Tag: Kea-2.3.6~82 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7efe36286c5634af5641f47d43d4acdd58f8f4f3;p=thirdparty%2Fkea.git [#719] Reapplied patch --- diff --git a/configure.ac b/configure.ac index 6ad90b2cad..914868d387 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/doc/examples/kea4/all-keys-netconf.json b/doc/examples/kea4/all-keys-netconf.json index c333464799..8aa6366904 100644 --- a/doc/examples/kea4/all-keys-netconf.json +++ b/doc/examples/kea4/all-keys-netconf.json @@ -568,6 +568,13 @@ // 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" @@ -890,6 +897,10 @@ // 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" diff --git a/doc/examples/kea4/all-keys.json b/doc/examples/kea4/all-keys.json index ee29cbf146..ccf01dde1f 100644 --- a/doc/examples/kea4/all-keys.json +++ b/doc/examples/kea4/all-keys.json @@ -604,6 +604,13 @@ // 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" @@ -934,6 +941,10 @@ // 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" diff --git a/doc/examples/kea6/all-keys-netconf.json b/doc/examples/kea6/all-keys-netconf.json index b3a043cd40..990adf4a6d 100644 --- a/doc/examples/kea6/all-keys-netconf.json +++ b/doc/examples/kea6/all-keys-netconf.json @@ -484,6 +484,13 @@ // 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" @@ -829,6 +836,10 @@ // 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" diff --git a/doc/examples/kea6/all-keys.json b/doc/examples/kea6/all-keys.json index e657492e15..81e113c309 100644 --- a/doc/examples/kea6/all-keys.json +++ b/doc/examples/kea6/all-keys.json @@ -518,6 +518,13 @@ // 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" @@ -879,6 +886,10 @@ // 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" diff --git a/doc/sphinx/arm/dhcp4-srv.rst b/doc/sphinx/arm/dhcp4-srv.rst index 649415f124..149988a298 100644 --- a/doc/sphinx/arm/dhcp4-srv.rst +++ b/doc/sphinx/arm/dhcp4-srv.rst @@ -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 diff --git a/doc/sphinx/arm/dhcp6-srv.rst b/doc/sphinx/arm/dhcp6-srv.rst index 4e0b4605aa..594d6c4aaf 100644 --- a/doc/sphinx/arm/dhcp6-srv.rst +++ b/doc/sphinx/arm/dhcp6-srv.rst @@ -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 diff --git a/src/bin/admin/tests/mysql_tests.sh.in b/src/bin/admin/tests/mysql_tests.sh.in index ceb541c599..403d51ea98 100644 --- a/src/bin/admin/tests/mysql_tests.sh.in +++ b/src/bin/admin/tests/mysql_tests.sh.in @@ -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 diff --git a/src/bin/admin/tests/pgsql_tests.sh.in b/src/bin/admin/tests/pgsql_tests.sh.in index a9704c394f..275f4df958 100644 --- a/src/bin/admin/tests/pgsql_tests.sh.in +++ b/src/bin/admin/tests/pgsql_tests.sh.in @@ -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 diff --git a/src/bin/dhcp4/dhcp4_lexer.ll b/src/bin/dhcp4/dhcp4_lexer.ll index 992810232d..ed105269d6 100644 --- a/src/bin/dhcp4/dhcp4_lexer.ll +++ b/src/bin/dhcp4/dhcp4_lexer.ll @@ -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: diff --git a/src/bin/dhcp4/dhcp4_parser.yy b/src/bin/dhcp4/dhcp4_parser.yy index 255d89cbab..98c8d3c4cb 100644 --- a/src/bin/dhcp4/dhcp4_parser.yy +++ b/src/bin/dhcp4/dhcp4_parser.yy @@ -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. diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index df565b0d87..d5010555e6 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -1841,33 +1841,50 @@ Dhcpv4Srv::appendRequestedOptions(Dhcpv4Exchange& ex) { } } - // Iterate on the configured option list to add persistent options + std::set 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(desc->option_->getType()); static_cast(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(desc->option_->getType()); + static_cast(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 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 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 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(desc->option_->getType()); + static_cast(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(desc->option_->getType()); + static_cast(cancelled_opts.insert(code)); } - // Add the persistent option code to requested options - uint16_t code = desc->option_->getType(); - static_cast(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); diff --git a/src/bin/dhcp4/tests/config_backend_unittest.cc b/src/bin/dhcp4/tests/config_backend_unittest.cc index ce1b78d499..4cd146fe2e 100644 --- a/src/bin/dhcp4/tests/config_backend_unittest.cc +++ b/src/bin/dhcp4/tests/config_backend_unittest.cc @@ -337,21 +337,24 @@ TEST_F(Dhcp4CBTest, mergeOptions) { // Add host-name to the first backend. opt.reset(new OptionDescriptor( createOption(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(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(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); diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc index d04c3f7e3f..4077ce15db 100644 --- a/src/bin/dhcp4/tests/config_parser_unittest.cc +++ b/src/bin/dhcp4/tests/config_parser_unittest.cc @@ -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); diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc index d4d3acfc9f..c4b7064a86 100644 --- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc @@ -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(); diff --git a/src/bin/dhcp4/tests/dhcp4_test_utils.cc b/src/bin/dhcp4/tests/dhcp4_test_utils.cc index 01596e6550..7bfbe01550 100644 --- a/src/bin/dhcp4/tests/dhcp4_test_utils.cc +++ b/src/bin/dhcp4/tests/dhcp4_test_utils.cc @@ -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(); diff --git a/src/bin/dhcp4/tests/get_config_unittest.cc b/src/bin/dhcp4/tests/get_config_unittest.cc index 11e722e4dc..be9b62dc69 100644 --- a/src/bin/dhcp4/tests/get_config_unittest.cc +++ b/src/bin/dhcp4/tests/get_config_unittest.cc @@ -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" diff --git a/src/bin/dhcp4/tests/vendor_opts_unittest.cc b/src/bin/dhcp4/tests/vendor_opts_unittest.cc index c0d485227b..8e61eb1745 100644 --- a/src/bin/dhcp4/tests/vendor_opts_unittest.cc +++ b/src/bin/dhcp4/tests/vendor_opts_unittest.cc @@ -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 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 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 vendor_resp = + boost::dynamic_pointer_cast(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 diff --git a/src/bin/dhcp6/dhcp6_lexer.ll b/src/bin/dhcp6/dhcp6_lexer.ll index 3d27fe151c..d9064e5d84 100644 --- a/src/bin/dhcp6/dhcp6_lexer.ll +++ b/src/bin/dhcp6/dhcp6_lexer.ll @@ -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: diff --git a/src/bin/dhcp6/dhcp6_parser.yy b/src/bin/dhcp6/dhcp6_parser.yy index 115980c65c..759f57afe0 100644 --- a/src/bin/dhcp6/dhcp6_parser.yy +++ b/src/bin/dhcp6/dhcp6_parser.yy @@ -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. diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 9709f3bc6d..c250cef3fa 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -1492,28 +1492,46 @@ Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer, } } - // Iterate on the configured option list to add persistent options + set 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(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(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 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 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 > 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(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(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); diff --git a/src/bin/dhcp6/tests/classify_unittests.cc b/src/bin/dhcp6/tests/classify_unittests.cc index d22a67f9f4..2116c08be7 100644 --- a/src/bin/dhcp6/tests/classify_unittests.cc +++ b/src/bin/dhcp6/tests/classify_unittests.cc @@ -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. diff --git a/src/bin/dhcp6/tests/config_backend_unittest.cc b/src/bin/dhcp6/tests/config_backend_unittest.cc index ce2842944e..ba16a90495 100644 --- a/src/bin/dhcp6/tests/config_backend_unittest.cc +++ b/src/bin/dhcp6/tests/config_backend_unittest.cc @@ -325,14 +325,15 @@ TEST_F(Dhcp6CBTest, mergeOptions) { // Add solmax-rt to the first backend. opt.reset(new OptionDescriptor( createOption(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(Option::V6, D6O_SOL_MAX_RT, - false, true, 700))); + false, false, true, 700))); opt->space_name_ = DHCP6_OPTION_SPACE; db2_->createUpdateOption6(ServerSelector::ALL(), opt); diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index 4dab6a13b7..51344d0c38 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -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); diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index ad9bcf0017..2c63c5623c 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -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(); diff --git a/src/bin/dhcp6/tests/get_config_unittest.cc b/src/bin/dhcp6/tests/get_config_unittest.cc index 842805f1d7..72ac7b89a3 100644 --- a/src/bin/dhcp6/tests/get_config_unittest.cc +++ b/src/bin/dhcp6/tests/get_config_unittest.cc @@ -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 #include #include -#include #include #include @@ -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" diff --git a/src/bin/dhcp6/tests/vendor_opts_unittest.cc b/src/bin/dhcp6/tests/vendor_opts_unittest.cc index d96dbcbe3d..f179e2ff00 100644 --- a/src/bin/dhcp6/tests/vendor_opts_unittest.cc +++ b/src/bin/dhcp6/tests/vendor_opts_unittest.cc @@ -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 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 vendor_resp = + boost::dynamic_pointer_cast(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) { diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc index 307a982bec..c596bb7dba 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc @@ -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(), // pool option: persistent + MySqlBinding::createInteger(), // pool option: cancelled MySqlBinding::createInteger(), // pool option: dhcp4_subnet_id MySqlBinding::createInteger(), // 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(), // option: persistent + MySqlBinding::createInteger(), // option: cancelled MySqlBinding::createInteger(), // option: dhcp4_subnet_id MySqlBinding::createInteger(), // 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 - (out_bindings[61]->getInteger())); + 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 + (out_bindings[63]->getInteger())); } - // 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()); + 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()); + } + + // 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()), IOAddress(out_bindings[22]->getInteger())); - // 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())) { last_pool_option_id = out_bindings[25]->getInteger(); @@ -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())) { - last_option_id = out_bindings[37]->getInteger(); + // Parse subnet-specific option from 38 to 50. + if (!out_bindings[38]->amNull() && + (last_option_id < out_bindings[38]->getInteger())) { + last_option_id = out_bindings[38]->getInteger(); - 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(), // pool option: persistent + MySqlBinding::createInteger(), // pool option: cancelled MySqlBinding::createInteger(), // pool option: dhcp4_subnet_id MySqlBinding::createInteger(), // 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(), // option: persistent + MySqlBinding::createInteger(), // option: cancelled MySqlBinding::createInteger(), // option: dhcp4_subnet_id MySqlBinding::createInteger(), // 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())); + 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())); } - // 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 - (out_bindings[37]->getInteger())); + 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 + (out_bindings[38]->getInteger())); } - // 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()); + 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()); + } + + // 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())) { last_option_id = out_bindings[13]->getInteger(); @@ -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(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(static_cast(subnet_id)), MySqlBinding::createInteger(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(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(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(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(), // option: persistent + MySqlBinding::createInteger(), // option: cancelled MySqlBinding::createInteger(), // option: dhcp4_subnet_id MySqlBinding::createInteger(), // 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())) { last_option_id = out_bindings[24]->getInteger(); diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc index 83b37141a2..05c7da5328 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc @@ -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(), // pool option: persistent + MySqlBinding::createInteger(), // pool option: cancelled MySqlBinding::createInteger(), // pool option: dhcp6_subnet_id MySqlBinding::createInteger(), // 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(), // pd pool option: persistent + MySqlBinding::createInteger(), // pd pool option: cancelled MySqlBinding::createInteger(), // pd pool option: dhcp6_subnet_id MySqlBinding::createInteger(), // 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(), // option: persistent + MySqlBinding::createInteger(), // option: cancelled MySqlBinding::createInteger(), // option: dhcp6_subnet_id MySqlBinding::createInteger(), // 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 - (out_bindings[84]->getInteger())); + 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 + (out_bindings[87]->getInteger())); } - // 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()); + 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()); + } + + // 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(), out_bindings[23]->getInteger(), excluded_prefix, - out_bindings[77]->getInteger()); + out_bindings[80]->getInteger()); - // 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())) { last_pool_option_id = out_bindings[26]->getInteger(); @@ -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())) { - last_pd_pool_option_id = out_bindings[39]->getInteger(); + // 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())) { + last_pd_pool_option_id = out_bindings[40]->getInteger(); - 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())) { - last_option_id = out_bindings[52]->getInteger(); + // Parse subnet specific option between 54 and 67 + if (!out_bindings[54]->amNull() && + (last_option_id < out_bindings[54]->getInteger())) { + last_option_id = out_bindings[54]->getInteger(); - 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(), // pool option: persistent + MySqlBinding::createInteger(), // pool option: cancelled MySqlBinding::createInteger(), // pool option: dhcp6_subnet_id MySqlBinding::createInteger(), // 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(), // pd pool option: persistent + MySqlBinding::createInteger(), // pd pool option: cancelled MySqlBinding::createInteger(), // pd pool option: dhcp6_subnet_id MySqlBinding::createInteger(), // 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())) { last_pd_pool_option_id = out_bindings[11]->getInteger(); @@ -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(), // option: persistent + MySqlBinding::createInteger(), // option: cancelled MySqlBinding::createInteger(), // option: dhcp6_subnet_id MySqlBinding::createInteger(), // 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 - (out_bindings[38]->getInteger())); + 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 + (out_bindings[39]->getInteger())); } - // 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()); + last_network->setCacheThreshold(out_bindings[44]->getFloat()); + } + + // cache_max_age at 45. + if (!out_bindings[45]->amNull()) { + last_network->setCacheMaxAge(out_bindings[45]->getInteger()); } - // 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())) { last_option_id = out_bindings[14]->getInteger(); @@ -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(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(static_cast(subnet_id)), MySqlBinding::createInteger(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(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(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(), // option: persistent + MySqlBinding::createInteger(), // option: cancelled MySqlBinding::createInteger(), // option: dhcp6_subnet_id MySqlBinding::createInteger(), // 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())) { last_option_id = out_bindings[21]->getInteger(); diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc index f4a05637f3..dafe462190 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc @@ -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()); + // cancelled + out_bindings.push_back(MySqlBinding::createInteger()); // dhcp[46]_subnet_id out_bindings.push_back(MySqlBinding::createInteger()); // 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((*(first_binding + 5))->getIntegerOrDefault(0)); + // Check if the option is cancelled. + bool cancelled = static_cast((*(first_binding + 6))->getIntegerOrDefault(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()) { diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h index 2422a601c7..24d4152b7e 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h @@ -562,6 +562,7 @@ public: /// - formatted_value, /// - space, /// - persistent, + /// - cancelled, /// - dhcp4_subnet_id/dhcp6_subnet_id, /// - scope_id, /// - user_context, diff --git a/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h b/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h index f0525d44b3..2f8906239c 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h +++ b/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h @@ -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 = ?," \ diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc index afaceced64..dfd5b2ae82 100644 --- a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc @@ -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(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(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(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(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. diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc index acf6e4aa20..12dbfc0997 100644 --- a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc @@ -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(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(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(worker.getSmallInt(22)), static_cast(worker.getSmallInt(23)), excluded_prefix, - static_cast(worker.getSmallInt(77))); + static_cast(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(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(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. diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc index 4399cb08a2..93e51a5e8d 100644 --- a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc @@ -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? diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h index 9c5532eb88..a1c9c693ec 100644 --- a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h @@ -496,6 +496,7 @@ public: /// - formatted_value, /// - space, /// - persistent, + /// - cancelled, /// - dhcp4_subnet_id/dhcp6_subnet_id, /// - scope_id, /// - user_context, diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h b/src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h index 375d914d96..8d459f197e 100644 --- a/src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h +++ b/src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h @@ -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 diff --git a/src/lib/dhcpsrv/cfg_option.cc b/src/lib/dhcpsrv/cfg_option.cc index ba88e6f5f1..a1d9e64589 100644 --- a/src/lib/dhcpsrv/cfg_option.cc +++ b/src/lib/dhcpsrv/cfg_option.cc @@ -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(opt, persist, formatted_value, + return (boost::make_shared(opt, persist, cancel, + formatted_value, user_context)); } OptionDescriptorPtr -OptionDescriptor::create(bool persist) { - return (boost::make_shared(persist)); +OptionDescriptor::create(bool persist, bool cancel) { + return (boost::make_shared(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 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 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); } diff --git a/src/lib/dhcpsrv/cfg_option.h b/src/lib/dhcpsrv/cfg_option.h index d2631d6f76..58aca4dce5 100644 --- a/src/lib/dhcpsrv/cfg_option.h +++ b/src/lib/dhcpsrv/cfg_option.h @@ -42,7 +42,7 @@ typedef std::vector 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, boost::multi_index::const_mem_fun + >, + // 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 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 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); diff --git a/src/lib/dhcpsrv/mysql_host_data_source.cc b/src/lib/dhcpsrv/mysql_host_data_source.cc index af1ffc9400..6af6dd2833 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.cc +++ b/src/lib/dhcpsrv/mysql_host_data_source.cc @@ -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(&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(&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(&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(&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(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(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(subnet_id_); - bind_[7].is_unsigned = MLM_TRUE; + bind_[8].buffer_type = MYSQL_TYPE_LONG; + bind_[8].buffer = reinterpret_cast(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(&host_id_); - bind_[8].is_unsigned = MLM_TRUE; + bind_[9].buffer_type = MYSQL_TYPE_LONG; + bind_[9].buffer = reinterpret_cast(&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, diff --git a/src/lib/dhcpsrv/parsers/option_data_parser.cc b/src/lib/dhcpsrv/parsers/option_data_parser.cc index e26e1c5e0b..6c09f8a8df 100644 --- a/src/lib/dhcpsrv/parsers/option_data_parser.cc +++ b/src/lib/dhcpsrv/parsers/option_data_parser.cc @@ -110,7 +110,7 @@ OptionDataParser::extractName(ConstElementPtr parent) const { return (Optional(name)); } -std::string +Optional 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()); } - return (data); + return (Optional(data)); } Optional @@ -186,6 +186,19 @@ OptionDataParser::extractPersistent(ConstElementPtr parent) const { return (Optional(persist)); } +Optional +OptionDataParser::extractCancelled(ConstElementPtr parent) const { + bool cancel = false; + try { + cancel = getBoolean(parent, "never-send"); + + } catch (...) { + return (Optional()); + } + + return (Optional(cancel)); +} + OptionDefinitionPtr OptionDataParser::findOptionDefinition(const std::string& option_space, const Optional& option_code, @@ -262,7 +275,8 @@ OptionDataParser::createOption(ConstElementPtr option_data) { Optional name_param = extractName(option_data); Optional csv_format_param = extractCSVFormat(option_data); Optional persist_param = extractPersistent(option_data); - std::string data_param = extractData(option_data); + Optional cancel_param = extractCancelled(option_data); + Optional 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(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 ************************* diff --git a/src/lib/dhcpsrv/parsers/option_data_parser.h b/src/lib/dhcpsrv/parsers/option_data_parser.h index a21cdf2c45..e8b47f2141 100644 --- a/src/lib/dhcpsrv/parsers/option_data_parser.h +++ b/src/lib/dhcpsrv/parsers/option_data_parser.h @@ -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 + 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 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 extractCancelled(data::ConstElementPtr parent) const; + /// @brief Address family: @c AF_INET or @c AF_INET6. uint16_t address_family_; diff --git a/src/lib/dhcpsrv/parsers/simple_parser4.cc b/src/lib/dhcpsrv/parsers/simple_parser4.cc index 2475fc49a6..551b001549 100644 --- a/src/lib/dhcpsrv/parsers/simple_parser4.cc +++ b/src/lib/dhcpsrv/parsers/simple_parser4.cc @@ -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. diff --git a/src/lib/dhcpsrv/parsers/simple_parser6.cc b/src/lib/dhcpsrv/parsers/simple_parser6.cc index eae89340c7..be310a3025 100644 --- a/src/lib/dhcpsrv/parsers/simple_parser6.cc +++ b/src/lib/dhcpsrv/parsers/simple_parser6.cc @@ -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. diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.cc b/src/lib/dhcpsrv/pgsql_host_data_source.cc index a1251be692..ed4de15554 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.cc +++ b/src/lib/dhcpsrv/pgsql_host_data_source.cc @@ -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 diff --git a/src/lib/dhcpsrv/tests/cb_ctl_dhcp_unittest.cc b/src/lib/dhcpsrv/tests/cb_ctl_dhcp_unittest.cc index 43a2f79c62..8c67343ae0 100644 --- a/src/lib/dhcpsrv/tests/cb_ctl_dhcp_unittest.cc +++ b/src/lib/dhcpsrv/tests/cb_ctl_dhcp_unittest.cc @@ -337,7 +337,8 @@ public: // Insert global options into the database. OptionDescriptorPtr opt(new OptionDescriptor(createOption (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 (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 (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 (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_); diff --git a/src/lib/dhcpsrv/tests/cfg_option_unittest.cc b/src/lib/dhcpsrv/tests/cfg_option_unittest.cc index b6692d20cc..acc3ca67aa 100644 --- a/src/lib/dhcpsrv/tests/cfg_option_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_option_unittest.cc @@ -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(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(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(code))); + ASSERT_NO_THROW(cfg.add(option, false, false, "foo", + static_cast(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(code))); + ASSERT_NO_THROW(cfg.add(option, false, false, "bar", + static_cast(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(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(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(code))); + ASSERT_NO_THROW(cfg.add(option, false, false, "vendor-123", + static_cast(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(expected, cfg); } diff --git a/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc b/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc index 4c49218f2c..9a1a731931 100644 --- a/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc @@ -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. diff --git a/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc b/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc index 53a2fa8bb1..57e1053b12 100644 --- a/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc @@ -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. diff --git a/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc b/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc index da23ec3a04..788ad0f51e 100644 --- a/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc @@ -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"))); diff --git a/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc b/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc index c86e190091..b9762c8b82 100644 --- a/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc @@ -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. diff --git a/src/lib/dhcpsrv/tests/client_class_def_unittest.cc b/src/lib/dhcpsrv/tests/client_class_def_unittest.cc index e7894a52c3..e89696927b 100644 --- a/src/lib/dhcpsrv/tests/client_class_def_unittest.cc +++ b/src/lib/dhcpsrv/tests/client_class_def_unittest.cc @@ -65,7 +65,7 @@ TEST(ClientClassDef, copyConstruction) { auto cfg_option = boost::make_shared(); auto option = boost::make_shared