From d26a72f5605b00bc97d0656924c13f737576298b Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 11 Nov 2020 19:06:06 +0200 Subject: [PATCH] [#1405] merged second pass --- src/bin/admin/tests/mysql_tests.sh.in | 112 ++++++--- src/bin/dhcp4/dhcp4_lexer.ll | 66 ++--- src/bin/dhcp4/dhcp4_parser.yy | 30 +-- src/bin/dhcp4/dhcp4_srv.cc | 11 +- src/bin/dhcp4/json_config_parser.cc | 58 +---- src/bin/dhcp4/tests/config_parser_unittest.cc | 237 +++++------------- src/bin/dhcp4/tests/dora_unittest.cc | 2 +- src/bin/dhcp6/dhcp6_lexer.ll | 66 ++--- src/bin/dhcp6/dhcp6_parser.yy | 30 +-- src/bin/dhcp6/dhcp6_srv.cc | 7 +- src/bin/dhcp6/json_config_parser.cc | 65 +---- src/bin/dhcp6/tests/config_parser_unittest.cc | 236 +++++------------ src/bin/dhcp6/tests/sarr_unittest.cc | 4 +- src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc | 164 ++++++------ src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc | 222 ++++++++-------- .../dhcp/mysql_cb/mysql_query_macros_dhcp.h | 16 +- .../mysql_cb/tests/mysql_cb_dhcp4_unittest.cc | 28 ++- .../mysql_cb/tests/mysql_cb_dhcp6_unittest.cc | 28 ++- src/lib/dhcpsrv/alloc_engine.cc | 91 +++---- .../dhcpsrv/parsers/base_network_parser.cc | 109 ++++---- src/lib/dhcpsrv/parsers/base_network_parser.h | 38 ++- src/lib/dhcpsrv/parsers/dhcp_parsers.cc | 28 +-- .../dhcpsrv/parsers/shared_network_parser.cc | 26 +- .../dhcpsrv/tests/alloc_engine4_unittest.cc | 1 + .../dhcpsrv/tests/alloc_engine6_unittest.cc | 2 + src/lib/dhcpsrv/tests/network_unittest.cc | 155 ++++++++++++ 26 files changed, 881 insertions(+), 951 deletions(-) diff --git a/src/bin/admin/tests/mysql_tests.sh.in b/src/bin/admin/tests/mysql_tests.sh.in index ba3a3b5227..ec12eafe06 100644 --- a/src/bin/admin/tests/mysql_tests.sh.in +++ b/src/bin/admin/tests/mysql_tests.sh.in @@ -766,6 +766,52 @@ insert into hosts(dhcp_identifier, dhcp_identifier_type, dhcp4_subnet_id, ipv4_a ERRCODE=$? assert_eq 0 $ERRCODE "insert into hosts failed, expected exit code %d, actual %d" + # Schema upgrade from 9.4 to 9.5. + + # table: dhcp4_shared_network (reservation_mode replaced by reservations flags) + qry="select reservations_global, reservations_in_subnet, reservations_out_of_pool from dhcp4_shared_network" + run_statement "dhcp4_shared_network" "$qry" + + qry="show columns from dhcp4_shared_network like 'reservation_mode'"; + text=`mysql_execute "${qry}"` + ERRCODE=$? + assert_eq 0 $ERRCODE "show columns from dhcp4_shared_network like 'reservation_mode' failed. (expected status code %d, returned %d)" + count=`echo $text | grep -ic reservation` + assert_eq $count 0 "dhcp4_shared_network has still reservation_mode column. (returned count %d, expected %d)" + + # table: dhcp4_subnet (reservation_mode replaced by reservations flags) + qry="select reservations_global, reservations_in_subnet, reservations_out_of_pool from dhcp4_subnet" + run_statement "dhcp4_subnet" "$qry" + + qry="show columns from dhcp4_subnet like 'reservation_mode'"; + text=`mysql_execute "${qry}"` + ERRCODE=$? + assert_eq 0 $ERRCODE "show columns from dhcp4_subnet like 'reservation_mode' failed. (expected status code %d, returned %d)" + count=`echo $text | grep -ic reservation` + assert_eq $count 0 "dhcp4_subnet has still reservation_mode column. (returned count %d, expected %d)" + + # table: dhcp6_shared_network (reservation_mode replaced by reservations flags) + qry="select reservations_global, reservations_in_subnet, reservations_out_of_pool from dhcp6_shared_network" + run_statement "dhcp6_shared_network" "$qry" + + qry="show columns from dhcp6_shared_network like 'reservation_mode'"; + text=`mysql_execute "${qry}"` + ERRCODE=$? + assert_eq 0 $ERRCODE "show columns from dhcp6_shared_network like 'reservation_mode' failed. (expected status code %d, returned %d)" + count=`echo $text | grep -ic reservation` + assert_eq $count 0 "dhcp6_shared_network has still reservation_mode column. (returned count %d, expected %d)" + + # table: dhcp6_subnet (reservation_mode replaced by reservations flags) + qry="select reservations_global, reservations_in_subnet, reservations_out_of_pool from dhcp6_subnet" + run_statement "dhcp6_subnet" "$qry" + + qry="show columns from dhcp6_subnet like 'reservation_mode'"; + text=`mysql_execute "${qry}"` + ERRCODE=$? + assert_eq 0 $ERRCODE "show columns from dhcp6_subnet like 'reservation_mode' failed. (expected status code %d, returned %d)" + count=`echo $text | grep -ic reservation` + assert_eq $count 0 "dhcp6_subnet has still reservation_mode column. (returned count %d, expected %d)" + # Verify upgraded schema reports version 9.5 version=$(${keaadmin} db-version mysql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir) assert_str_eq "9.5" ${version} "Expected kea-admin to return %s, returned value was %s" @@ -1352,7 +1398,7 @@ mysql_unused_subnet_id_test() { # Verifies that you can upgrade from an earlier version and # that reservation_mode values in subnet and shared network tables are -# converted to new values. +# converted to new reservations flags. mysql_reservation_mode_upgrade_test() { test_start "mysql_reservation_mode_upgrade_test" @@ -1422,68 +1468,68 @@ mysql_reservation_mode_upgrade_test() { # Upgrade to schema 9.5. mysql_upgrade_schema_to_version 9.5 - # Test DISABLED (0) -> 0 - qry="select count(id) from dhcp4_shared_network where reservation_mode = 0 and name = 'test0';" + # Test DISABLED (0) -> false, false, false + qry="select count(id) from dhcp4_shared_network where reservations_global = false and reservations_in_subnet = false and reservations_out_of_pool = false and name = 'test0';" run_statement "#4_shared_disabled" "$qry" 1 - # Test OUT_OF_POOL (1) -> 3 - qry="select count(id) from dhcp4_shared_network where reservation_mode = 3 and name = 'test1';" + # Test OUT_OF_POOL (1) -> false, true, true + qry="select count(id) from dhcp4_shared_network where reservations_global = false and reservations_in_subnet = true and reservations_out_of_pool = true and name = 'test1';" run_statement "#4_shared_out_of_pool" "$qry" 1 - # Test GLOBAL (2) -> 4 - qry="select count(id) from dhcp4_shared_network where reservation_mode = 4 and name = 'test2';" + # Test GLOBAL (2) -> true, false, false + qry="select count(id) from dhcp4_shared_network where reservations_global = true and reservations_in_subnet = false and reservations_out_of_pool = false and name = 'test2';" run_statement "#4_shared_global" "$qry" 1 - # Test ALL (3) -> 2 - qry="select count(id) from dhcp4_shared_network where reservation_mode = 2 and name = 'test3';" + # Test ALL (3) -> false, true, false + qry="select count(id) from dhcp4_shared_network where reservation_global = false and reservations_in_subnet = true and reservations_out_of_pool = false name = 'test3';" run_statement "#4_shared_all" "$qry" 1 - # Test DISABLED (0) -> 0 - qry="select count(subnet_id) from dhcp4_subnet where reservation_mode = 0 and subnet_prefix = '192.0.0.0/24'" + # Test DISABLED (0) -> false, false, false + qry="select count(subnet_id) from dhcp4_subnet where reservations_global = false and reservations_in_subnet = false and reservations_out_of_pool = false and subnet_prefix = '192.0.0.0/24'" run_statement "#4_subnet_disabled" "$qry" 1 - # Test OUT_OF_POOL (1) -> 3 - qry="select count(subnet_id) from dhcp4_subnet where reservation_mode = 3 and subnet_prefix = '192.0.1.0/24'" + # Test OUT_OF_POOL (1) -> false, true, true + qry="select count(subnet_id) from dhcp4_subnet where reservations_global = false and reservations_in_subnet = true and reservations_out_of_pool = true and subnet_prefix = '192.0.1.0/24'" run_statement "#4_subnet_out_of_pool" "$qry" 1 - # Test GLOBAL (2) -> 4 - qry="select count(subnet_id) from dhcp4_subnet where reservation_mode = 4 and subnet_prefix = '192.0.2.0/24'" + # Test GLOBAL (2) -> true, false, false + qry="select count(subnet_id) from dhcp4_subnet where reservations_global = true and reservations_in_subnet = false and reservations_out_of_pool = false and subnet_prefix = '192.0.2.0/24'" run_statement "#4_subnet_global" "$qry" 1 - # Test ALL (3) -> 2 - qry="select count(subnet_id) from dhcp4_subnet where reservation_mode = 2 and subnet_prefix = '192.0.3.0/24'" + # Test ALL (3) -> false, true, false + qry="select count(subnet_id) from dhcp4_subnet where reservations_global = false and reservations_in_subnet = true and reservations_out_of_pool = false and subnet_prefix = '192.0.3.0/24'" run_statement "#4_subnet_all" "$qry" 1 - # Test DISABLED (0) -> 0 - qry="select count(id) from dhcp6_shared_network where reservation_mode = 0 and name = 'test0';" + # Test DISABLED (0) -> false, false, false + qry="select count(id) from dhcp6_shared_network where reservations_global = false and reservations_in_subnet = false and reservations_out_of_pool = false and name = 'test0';" run_statement "#6_shared_disabled" "$qry" 1 - # Test OUT_OF_POOL (1) -> 3 - qry="select count(id) from dhcp6_shared_network where reservation_mode = 3 and name = 'test1';" + # Test OUT_OF_POOL (1) -> false, true, true + qry="select count(id) from dhcp6_shared_network where reservations_global = false and reservations_in_subnet = true and reservations_out_of_pool = true and name = 'test1';" run_statement "#6_shared_out_of_pool" "$qry" 1 - # Test GLOBAL (2) -> 4 - qry="select count(id) from dhcp6_shared_network where reservation_mode = 4 and name = 'test2';" + # Test GLOBAL (2) -> true, false, false + qry="select count(id) from dhcp6_shared_network where reservations_global = true and reservations_in_subnet = false and reservations_out_of_pool = false and name = 'test2';" run_statement "#6_shared_global" "$qry" 1 - # Test ALL (3) -> 2 - qry="select count(id) from dhcp6_shared_network where reservation_mode = 2 and name = 'test3';" + # Test ALL (3) -> false, true, false + qry="select count(id) from dhcp6_shared_network where reservations_global = false and reservations_in_subnet = true and reservations_out_of_pool = false and name = 'test3';" run_statement "#6_shared_all" "$qry" 1 - # Test DISABLED (0) -> 0 - qry="select count(subnet_id) from dhcp6_subnet where reservation_mode = 0 and subnet_prefix = '2001:db8::/64'" + # Test DISABLED (0) -> false, false, false + qry="select count(subnet_id) from dhcp6_subnet where reservations_global = false and reservations_in_subnet = false and reservations_out_of_pool = false and subnet_prefix = '2001:db8::/64'" run_statement "#6_subnet_disabled" "$qry" 1 - # Test OUT_OF_POOL (1) -> 3 - qry="select count(subnet_id) from dhcp6_subnet where reservation_mode = 3 and subnet_prefix = '2001:db8:1::/64'" + # Test OUT_OF_POOL (1) -> false, true, true + qry="select count(subnet_id) from dhcp6_subnet where reservations_global = false and reservations_in_subnet = true and reservations_out_of_pool = true and subnet_prefix = '2001:db8:1::/64'" run_statement "#6_subnet_out_of_pool" "$qry" 1 - # Test GLOBAL (2) -> 4 - qry="select count(subnet_id) from dhcp6_subnet where reservation_mode = 4 and subnet_prefix = '2001:db8:2::/64'" + # Test GLOBAL (2) -> true, false, false + qry="select count(subnet_id) from dhcp6_subnet where reservations_global = true and reservations_in_subnet = false and reservations_out_of_pool = false and subnet_prefix = '2001:db8:2::/64'" run_statement "#6_subnet_global" "$qry" 1 - # Test ALL (3) -> 2 - qry="select count(subnet_id) from dhcp6_subnet where reservation_mode = 2 and subnet_prefix = '2001:db8:3::/64'" + # Test ALL (3) -> false, true, false + qry="select count(subnet_id) from dhcp6_subnet where reservations_global = false and reservations_in_subnet = true and reservations_out_of_pool = false and subnet_prefix = '2001:db8:3::/64'" run_statement "#6_subnet_all" "$qry" 1 qry="select count(*) from dhcp4_shared_network;" diff --git a/src/bin/dhcp4/dhcp4_lexer.ll b/src/bin/dhcp4/dhcp4_lexer.ll index 3083980b5f..70a8cbc2c9 100644 --- a/src/bin/dhcp4/dhcp4_lexer.ll +++ b/src/bin/dhcp4/dhcp4_lexer.ll @@ -948,39 +948,6 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu] } } -\"reservations-out-of-pool\" { - switch(driver.ctx_) { - case isc::dhcp::Parser4Context::DHCP4: - case isc::dhcp::Parser4Context::SUBNET4: - case isc::dhcp::Parser4Context::SHARED_NETWORK: - return isc::dhcp::Dhcp4Parser::make_RESERVATIONS_OUT_OF_POOL(driver.loc_); - default: - return isc::dhcp::Dhcp4Parser::make_STRING("reservations-out-of-pool", driver.loc_); - } -} - -\"reservations-in-subnet\" { - switch(driver.ctx_) { - case isc::dhcp::Parser4Context::DHCP4: - case isc::dhcp::Parser4Context::SUBNET4: - case isc::dhcp::Parser4Context::SHARED_NETWORK: - return isc::dhcp::Dhcp4Parser::make_RESERVATIONS_IN_SUBNET(driver.loc_); - default: - return isc::dhcp::Dhcp4Parser::make_STRING("reservations-in-subnet", driver.loc_); - } -} - -\"reservations-global\" { - switch(driver.ctx_) { - case isc::dhcp::Parser4Context::DHCP4: - case isc::dhcp::Parser4Context::SUBNET4: - case isc::dhcp::Parser4Context::SHARED_NETWORK: - return isc::dhcp::Dhcp4Parser::make_RESERVATIONS_GLOBAL(driver.loc_); - default: - return isc::dhcp::Dhcp4Parser::make_STRING("reservations-global", driver.loc_); - } -} - \"reservation-mode\" { switch(driver.ctx_) { case isc::dhcp::Parser4Context::DHCP4: @@ -1037,6 +1004,39 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu] } } +\"reservations-global\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::DHCP4: + case isc::dhcp::Parser4Context::SUBNET4: + case isc::dhcp::Parser4Context::SHARED_NETWORK: + return isc::dhcp::Dhcp4Parser::make_RESERVATIONS_GLOBAL(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("reservations-global", driver.loc_); + } +} + +\"reservations-in-subnet\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::DHCP4: + case isc::dhcp::Parser4Context::SUBNET4: + case isc::dhcp::Parser4Context::SHARED_NETWORK: + return isc::dhcp::Dhcp4Parser::make_RESERVATIONS_IN_SUBNET(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("reservations-in-subnet", driver.loc_); + } +} + +\"reservations-out-of-pool\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::DHCP4: + case isc::dhcp::Parser4Context::SUBNET4: + case isc::dhcp::Parser4Context::SHARED_NETWORK: + return isc::dhcp::Dhcp4Parser::make_RESERVATIONS_OUT_OF_POOL(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("reservations-out-of-pool", driver.loc_); + } +} + \"code\" { switch(driver.ctx_) { case isc::dhcp::Parser4Context::OPTION_DEF: diff --git a/src/bin/dhcp4/dhcp4_parser.yy b/src/bin/dhcp4/dhcp4_parser.yy index 8b9624bfad..531a57b37f 100644 --- a/src/bin/dhcp4/dhcp4_parser.yy +++ b/src/bin/dhcp4/dhcp4_parser.yy @@ -152,13 +152,13 @@ using namespace std; INTERFACE "interface" ID "id" RESERVATION_MODE "reservation-mode" - RESERVATIONS_OUT_OF_POOL "reservations-out-of-pool" - RESERVATIONS_IN_SUBNET "reservations-in-subnet" - RESERVATIONS_GLOBAL "reservations-global" DISABLED "disabled" OUT_OF_POOL "out-of-pool" GLOBAL "global" ALL "all" + RESERVATIONS_GLOBAL "reservations-global" + RESERVATIONS_IN_SUBNET "reservations-in-subnet" + RESERVATIONS_OUT_OF_POOL "reservations-out-of-pool" HOST_RESERVATION_IDENTIFIERS "host-reservation-identifiers" @@ -486,9 +486,9 @@ global_param: valid_lifetime | config_control | server_tag | reservation_mode - | reservations_out_of_pool - | reservations_in_subnet | reservations_global + | reservations_in_subnet + | reservations_out_of_pool | calculate_tee_times | t1_percent | t2_percent @@ -1374,9 +1374,9 @@ subnet4_param: valid_lifetime | require_client_classes | reservations | reservation_mode - | reservations_out_of_pool - | reservations_in_subnet | reservations_global + | reservations_in_subnet + | reservations_out_of_pool | relay | match_client_id | authoritative @@ -1472,10 +1472,10 @@ require_client_classes: REQUIRE_CLIENT_CLASSES { ctx.leave(); }; -reservations_out_of_pool: RESERVATIONS_OUT_OF_POOL COLON BOOLEAN { - ctx.unique("reservations-out-of-pool", ctx.loc2pos(@1)); +reservations_global: RESERVATIONS_GLOBAL COLON BOOLEAN { + ctx.unique("reservations-global", ctx.loc2pos(@1)); ElementPtr b(new BoolElement($3, ctx.loc2pos(@3))); - ctx.stack_.back()->set("reservations-out-of-pool", b); + ctx.stack_.back()->set("reservations-global", b); }; reservations_in_subnet: RESERVATIONS_IN_SUBNET COLON BOOLEAN { @@ -1484,10 +1484,10 @@ reservations_in_subnet: RESERVATIONS_IN_SUBNET COLON BOOLEAN { ctx.stack_.back()->set("reservations-in-subnet", b); }; -reservations_global: RESERVATIONS_GLOBAL COLON BOOLEAN { - ctx.unique("reservations-global", ctx.loc2pos(@1)); +reservations_out_of_pool: RESERVATIONS_OUT_OF_POOL COLON BOOLEAN { + ctx.unique("reservations-out-of-pool", ctx.loc2pos(@1)); ElementPtr b(new BoolElement($3, ctx.loc2pos(@3))); - ctx.stack_.back()->set("reservations-global", b); + ctx.stack_.back()->set("reservations-out-of-pool", b); }; reservation_mode: RESERVATION_MODE { @@ -1558,9 +1558,9 @@ shared_network_param: name | boot_file_name | relay | reservation_mode - | reservations_out_of_pool - | reservations_in_subnet | reservations_global + | reservations_in_subnet + | reservations_out_of_pool | client_class | require_client_classes | valid_lifetime diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 12e705fb7a..56d64fe477 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -180,7 +180,9 @@ Dhcpv4Exchange::Dhcpv4Exchange(const AllocEnginePtr& alloc_engine, } // Find static reservations if not disabled for our subnet. - if (subnet->getHostReservationMode() != Network::HR_DISABLED) { + if (subnet->getReservationsGlobal() || + subnet->getReservationsInSubnet() || + subnet->getReservationsOutOfPool()) { // Before we can check for static reservations, we need to prepare a set // of identifiers to be used for this. setHostIdentifiers(); @@ -493,8 +495,11 @@ Dhcpv4Exchange::conditionallySetReservedClientClasses() { if (context_->subnet_) { SharedNetwork4Ptr shared_network; context_->subnet_->getSharedNetwork(shared_network); - if (shared_network && !context_->globalHost()) { - setReservedClientClasses(context_); + if (shared_network) { + ConstHostPtr host = context_->currentHost(); + if (host && (host->getIPv4SubnetID() != SUBNET_ID_GLOBAL)) { + setReservedClientClasses(context_); + } } } } diff --git a/src/bin/dhcp4/json_config_parser.cc b/src/bin/dhcp4/json_config_parser.cc index b5d54d17d6..d46cb63523 100644 --- a/src/bin/dhcp4/json_config_parser.cc +++ b/src/bin/dhcp4/json_config_parser.cc @@ -367,53 +367,17 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set, // default values and will insert derived values as well. mutable_cfg = boost::const_pointer_cast(config_set); - bool found = false; - ConstElementPtr reservations_out_of_pool = mutable_cfg->get("reservations-out-of-pool"); - ConstElementPtr reservations_in_subnet = mutable_cfg->get("reservations-in-subnet"); - ConstElementPtr reservations_global = mutable_cfg->get("reservations-global"); - if (reservations_out_of_pool || reservations_in_subnet || reservations_global) { - found = true; - } - ConstElementPtr reservation_mode = mutable_cfg->get("reservation-mode"); - if (reservation_mode) { - LOG_WARN(dhcp4_logger, DHCP4_DEPRECATED_RESERVATION_MODE); - if (found) { - isc_throw(DhcpConfigError, "invalid use of both 'reservation-mode'" - " and one of 'reservations-out-of-pool'" - " , 'reservations-in-subnet' or" - " 'reservations-global' parameters"); - } - } - - // reset all other reservation flags to overwrite default values. - if (found) { - bool force_true = false; - if (!reservations_out_of_pool) { - mutable_cfg->set("reservations-out-of-pool", Element::create(false)); - } else { - force_true = reservations_out_of_pool->boolValue(); - } - if (!reservations_in_subnet) { - if (force_true) { - mutable_cfg->set("reservations-in-subnet", Element::create(true)); - } else { - mutable_cfg->set("reservations-in-subnet", Element::create(false)); - } - } else if (force_true && !reservations_in_subnet->boolValue()) { - isc_throw(DhcpConfigError, "invalid use of disabled 'reservations-in-subnet'" - " when enabled 'reservations-out-of-pool'"); - } - if (!reservations_global) { - mutable_cfg->set("reservations-global", Element::create(false)); - } - } - // Relocate dhcp-ddns parameters that have moved to global scope. // Rule is that a global value overrides the dhcp-ddns value, so // we need to do this before we apply global defaults. // Note this is done for backward compatibility. srv_cfg->moveDdnsParams(mutable_cfg); + // Move from reservation mode to new reservations flags. + if (BaseNetworkParser::moveReservationMode(mutable_cfg)) { + LOG_WARN(dhcp4_logger, DHCP4_DEPRECATED_RESERVATION_MODE); + } + // Set all default values if not specified by the user. SimpleParser4::setAllDefaults(mutable_cfg); @@ -432,14 +396,6 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set, // Apply global options in the staging config, e.g. ip-reservations-unique global_parser.parseEarly(srv_cfg, mutable_cfg); - // If using deprecated reservation-mode, remove defaults for new parameters - // reservations-out-of-pool, reservations-in-subnet and reservations-global. - if (reservation_mode) { - mutable_cfg->remove("reservations-out-of-pool"); - mutable_cfg->remove("reservations-in-subnet"); - mutable_cfg->remove("reservations-global"); - } - // We need definitions first ConstElementPtr option_defs = mutable_cfg->get("option-def"); if (option_defs) { @@ -678,9 +634,9 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set, (config_pair.first == "boot-file-name") || (config_pair.first == "server-tag") || (config_pair.first == "reservation-mode") || - (config_pair.first == "reservations-out-of-pool") || - (config_pair.first == "reservations-in-subnet") || (config_pair.first == "reservations-global") || + (config_pair.first == "reservations-in-subnet") || + (config_pair.first == "reservations-out-of-pool") || (config_pair.first == "calculate-tee-times") || (config_pair.first == "t1-percent") || (config_pair.first == "t2-percent") || diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc index 2d05ce610b..79239c5178 100644 --- a/src/bin/dhcp4/tests/config_parser_unittest.cc +++ b/src/bin/dhcp4/tests/config_parser_unittest.cc @@ -5280,96 +5280,10 @@ TEST_F(Dhcp4ParserTest, reservationBogus) { checkResult(x, 1); } -/// The goal of this test is to verify that Host Reservation modes can be +/// The goal of this test is to verify that Host Reservation flags can be /// specified on a per-subnet basis. TEST_F(Dhcp4ParserTest, hostReservationPerSubnet) { - /// - Configuration: - /// - only addresses (no prefixes) - /// - 5 subnets with: - /// - 192.0.1.0/24 (all reservations enabled) - /// - 192.0.2.0/24 (out-of-pool reservations) - /// - 192.0.3.0/24 (reservations disabled) - /// - 192.0.4.0/24 (global reservations) - /// - 192.0.5.0/24 (reservations not specified) - const char* hr_config = - "{ " - "\"rebind-timer\": 2000, " - "\"renew-timer\": 1000, " - "\"subnet4\": [ { " - " \"pools\": [ { \"pool\": \"192.0.1.0/24\" } ]," - " \"subnet\": \"192.0.1.0/24\", " - " \"reservation-mode\": \"all\"" - " }," - " {" - " \"pools\": [ { \"pool\": \"192.0.2.0/24\" } ]," - " \"subnet\": \"192.0.2.0/24\", " - " \"reservation-mode\": \"out-of-pool\"" - " }," - " {" - " \"pools\": [ { \"pool\": \"192.0.3.0/24\" } ]," - " \"subnet\": \"192.0.3.0/24\", " - " \"reservation-mode\": \"disabled\"" - " }," - " {" - " \"pools\": [ { \"pool\": \"192.0.4.0/24\" } ]," - " \"subnet\": \"192.0.4.0/24\", " - " \"reservation-mode\": \"global\"" - " }," - " {" - " \"pools\": [ { \"pool\": \"192.0.5.0/24\" } ]," - " \"subnet\": \"192.0.5.0/24\"" - " } ]," - "\"valid-lifetime\": 4000 }"; - - ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP4(hr_config)); - extractConfig(hr_config); - ConstElementPtr result; - EXPECT_NO_THROW(result = configureDhcp4Server(*srv_, json)); - - // returned value should be 0 (success) - checkResult(result, 0); - - // Let's get all subnets and check that there are 5 of them. - ConstCfgSubnets4Ptr subnets = CfgMgr::instance().getStagingCfg()->getCfgSubnets4(); - ASSERT_TRUE(subnets); - const Subnet4Collection* subnet_col = subnets->getAll(); - ASSERT_EQ(5, subnet_col->size()); // We expect 5 subnets - - // Let's check if the parsed subnets have correct HR modes. - - // Subnet 1 - Subnet4Ptr subnet; - subnet = subnets->selectSubnet(IOAddress("192.0.1.1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); - - // Subnet 2 - subnet = subnets->selectSubnet(IOAddress("192.0.2.1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode()); - - // Subnet 3 - subnet = subnets->selectSubnet(IOAddress("192.0.3.1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_DISABLED, subnet->getHostReservationMode()); - - // Subnet 4 - subnet = subnets->selectSubnet(IOAddress("192.0.4.1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_GLOBAL, subnet->getHostReservationMode()); - - // Subnet 5 - subnet = subnets->selectSubnet(IOAddress("192.0.5.1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); -} - -/// The goal of this test is to verify that Host Reservation modes can be -/// specified on a per-subnet basis. -TEST_F(Dhcp4ParserTest, hostReservationModesPerSubnet) { - /// - Configuration: /// - only addresses (no prefixes) /// - 7 subnets with: @@ -5387,24 +5301,30 @@ TEST_F(Dhcp4ParserTest, hostReservationModesPerSubnet) { "\"subnet4\": [ { " " \"pools\": [ { \"pool\": \"192.0.1.0/24\" } ]," " \"subnet\": \"192.0.1.0/24\", " - " \"reservations-in-subnet\": true" + " \"reservations-global\": false," + " \"reservations-in-subnet\": true," + " \"reservations-out-of-pool\": false" " }," " {" " \"pools\": [ { \"pool\": \"192.0.2.0/24\" } ]," " \"subnet\": \"192.0.2.0/24\", " + " \"reservations-global\": false," + " \"reservations-in-subnet\": true," " \"reservations-out-of-pool\": true" " }," " {" " \"pools\": [ { \"pool\": \"192.0.3.0/24\" } ]," " \"subnet\": \"192.0.3.0/24\", " - " \"reservations-out-of-pool\": false," + " \"reservations-global\": false," " \"reservations-in-subnet\": false," - " \"reservations-global\": false" + " \"reservations-out-of-pool\": false" " }," " {" " \"pools\": [ { \"pool\": \"192.0.4.0/24\" } ]," " \"subnet\": \"192.0.4.0/24\", " - " \"reservations-global\": true" + " \"reservations-global\": true," + " \"reservations-in-subnet\": false," + " \"reservations-out-of-pool\": false" " }," " {" " \"pools\": [ { \"pool\": \"192.0.5.0/24\" } ]," @@ -5413,16 +5333,16 @@ TEST_F(Dhcp4ParserTest, hostReservationModesPerSubnet) { " {" " \"pools\": [ { \"pool\": \"192.0.6.0/24\" } ]," " \"subnet\": \"192.0.6.0/24\", " - " \"reservations-out-of-pool\": false," + " \"reservations-global\": true," " \"reservations-in-subnet\": true," - " \"reservations-global\": true" + " \"reservations-out-of-pool\": false" " }," " {" " \"pools\": [ { \"pool\": \"192.0.7.0/24\" } ]," " \"subnet\": \"192.0.7.0/24\", " - " \"reservations-out-of-pool\": true," + " \"reservations-global\": true," " \"reservations-in-subnet\": true," - " \"reservations-global\": true" + " \"reservations-out-of-pool\": true" " } ]," "\"valid-lifetime\": 4000 }"; @@ -5447,41 +5367,54 @@ TEST_F(Dhcp4ParserTest, hostReservationModesPerSubnet) { Subnet4Ptr subnet; subnet = subnets->selectSubnet(IOAddress("192.0.1.1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 2 subnet = subnets->selectSubnet(IOAddress("192.0.2.1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_TRUE(subnet->getReservationsOutOfPool()); // Subnet 3 subnet = subnets->selectSubnet(IOAddress("192.0.3.1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_DISABLED, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_FALSE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 4 subnet = subnets->selectSubnet(IOAddress("192.0.4.1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_GLOBAL, subnet->getHostReservationMode()); + EXPECT_TRUE(subnet->getReservationsGlobal()); + EXPECT_FALSE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 5 subnet = subnets->selectSubnet(IOAddress("192.0.5.1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 6 subnet = subnets->selectSubnet(IOAddress("192.0.6.1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL|Network::HR_GLOBAL, subnet->getHostReservationMode()); + EXPECT_TRUE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 7 subnet = subnets->selectSubnet(IOAddress("192.0.7.1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_OUT_OF_POOL|Network::HR_GLOBAL, - subnet->getHostReservationMode()); + EXPECT_TRUE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_TRUE(subnet->getReservationsOutOfPool()); } -/// The goal of this test is to verify that Host Reservation modes can be +/// The goal of this test is to verify that Host Reservation flags can be /// specified globally. TEST_F(Dhcp4ParserTest, hostReservationGlobal) { @@ -5494,73 +5427,15 @@ TEST_F(Dhcp4ParserTest, hostReservationGlobal) { "{ " "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " - "\"reservation-mode\": \"out-of-pool\", " - "\"subnet4\": [ { " - " \"pools\": [ { \"pool\": \"192.0.2.0/24\" } ]," - " \"subnet\": \"192.0.2.0/24\", " - " \"reservation-mode\": \"all\"" - " }," - " {" - " \"pools\": [ { \"pool\": \"192.0.3.0/24\" } ]," - " \"subnet\": \"192.0.3.0/24\"" - " } ]," - "\"valid-lifetime\": 4000 }"; - - ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP4(hr_config)); - extractConfig(hr_config); - ConstElementPtr result; - EXPECT_NO_THROW(result = configureDhcp4Server(*srv_, json)); - - // returned value should be 0 (success) - checkResult(result, 0); - - // Let's get all subnets and check that there are 4 of them. - ConstCfgSubnets4Ptr subnets = CfgMgr::instance().getStagingCfg()->getCfgSubnets4(); - ASSERT_TRUE(subnets); - const Subnet4Collection* subnet_col = subnets->getAll(); - ASSERT_EQ(2, subnet_col->size()); // We expect 2 subnets - - // Let's check if the parsed subnets have correct HR modes. - - // Subnet 1 - Subnet4Ptr subnet; - subnet = subnets->selectSubnet(IOAddress("192.0.2.1")); - ASSERT_TRUE(subnet); - // Reset the fetch global function to staging (vs current) config. - subnet->setFetchGlobalsFn([]() -> ConstElementPtr { - return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); - }); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); - - // Subnet 2 - subnet = subnets->selectSubnet(IOAddress("192.0.3.1")); - ASSERT_TRUE(subnet); - // Reset the fetch global function to staging (vs current) config. - subnet->setFetchGlobalsFn([]() -> ConstElementPtr { - return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); - }); - EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode()); -} - -/// The goal of this test is to verify that Host Reservation modes can be -/// specified globally. -TEST_F(Dhcp4ParserTest, hostReservationModesGlobal) { - - /// - Configuration: - /// - only addresses (no prefixes) - /// - 2 subnets with : - /// - 192.0.2.0/24 (all reservations enabled) - /// - 192.0.3.0/24 (reservations not specified) - const char* hr_config = - "{ " - "\"rebind-timer\": 2000, " - "\"renew-timer\": 1000, " + "\"reservations-global\": false," + "\"reservations-in-subnet\": true," "\"reservations-out-of-pool\": true," "\"subnet4\": [ { " " \"pools\": [ { \"pool\": \"192.0.2.0/24\" } ]," " \"subnet\": \"192.0.2.0/24\", " - " \"reservations-in-subnet\": true" + " \"reservations-global\": false," + " \"reservations-in-subnet\": true," + " \"reservations-out-of-pool\": false" " }," " {" " \"pools\": [ { \"pool\": \"192.0.3.0/24\" } ]," @@ -5593,7 +5468,9 @@ TEST_F(Dhcp4ParserTest, hostReservationModesGlobal) { subnet->setFetchGlobalsFn([]() -> ConstElementPtr { return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); }); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 2 subnet = subnets->selectSubnet(IOAddress("192.0.3.1")); @@ -5602,7 +5479,9 @@ TEST_F(Dhcp4ParserTest, hostReservationModesGlobal) { subnet->setFetchGlobalsFn([]() -> ConstElementPtr { return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); }); - EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_TRUE(subnet->getReservationsOutOfPool()); } /// Check that the decline-probation-period has a default value when not @@ -6459,7 +6338,9 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { " \"relay\": {\n" " \"ip-address\": \"5.6.7.8\"\n" " },\n" - " \"reservations-out-of-pool\": true," + " \"reservations-global\": false,\n" + " \"reservations-in-subnet\": true,\n" + " \"reservations-out-of-pool\": true,\n" " \"renew-timer\": 10,\n" " \"rebind-timer\": 20,\n" " \"valid-lifetime\": 40,\n" @@ -6485,7 +6366,9 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { " \"relay\": {\n" " \"ip-address\": \"55.66.77.88\"\n" " },\n" - " \"reservations-global\": false" + " \"reservations-global\": false,\n" + " \"reservations-in-subnet\": false,\n" + " \"reservations-out-of-pool\": false\n" " }\n" " ]\n" " },\n" @@ -6536,7 +6419,9 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { EXPECT_EQ("foo", s->getSname().get()); EXPECT_EQ("bar", s->getFilename().get()); EXPECT_TRUE(s->hasRelayAddress(IOAddress("5.6.7.8"))); - EXPECT_EQ(Network::HR_OUT_OF_POOL, s->getHostReservationMode()); + EXPECT_FALSE(s->getReservationsGlobal()); + EXPECT_TRUE(s->getReservationsInSubnet()); + EXPECT_TRUE(s->getReservationsOutOfPool()); // For the second subnet, the renew-timer should be 100, because it // was specified explicitly. Other parameters a derived @@ -6553,7 +6438,9 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { EXPECT_EQ("some-name.example.org", s->getSname().get()); EXPECT_EQ("bootfile.efi", s->getFilename().get()); EXPECT_TRUE(s->hasRelayAddress(IOAddress("55.66.77.88"))); - EXPECT_EQ(Network::HR_DISABLED, s->getHostReservationMode()); + EXPECT_FALSE(s->getReservationsGlobal()); + EXPECT_FALSE(s->getReservationsInSubnet()); + EXPECT_FALSE(s->getReservationsOutOfPool()); // Ok, now check the second shared subnet. net = nets->at(1); @@ -6574,7 +6461,9 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { EXPECT_TRUE(s->getSname().empty()); EXPECT_TRUE(s->getFilename().empty()); EXPECT_FALSE(s->hasRelays()); - EXPECT_EQ(Network::HR_ALL, s->getHostReservationMode()); + EXPECT_FALSE(s->getReservationsGlobal()); + EXPECT_TRUE(s->getReservationsInSubnet()); + EXPECT_FALSE(s->getReservationsOutOfPool()); } // This test checks if client-class is derived properly. diff --git a/src/bin/dhcp4/tests/dora_unittest.cc b/src/bin/dhcp4/tests/dora_unittest.cc index 3886e36e00..b380032ed5 100644 --- a/src/bin/dhcp4/tests/dora_unittest.cc +++ b/src/bin/dhcp4/tests/dora_unittest.cc @@ -1809,7 +1809,7 @@ TEST_F(DORATest, reservationModeDisabled) { // Set explicit HW address so as it matches the reservation in the // configuration used below. client.setHWAddress("aa:bb:cc:dd:ee:ff"); - // Configure DHCP server. In this configuration the reservation flags are + // Configure DHCP server. In this configuration the reservations flags are // set to false. Thus, the server should ignore the reservation for // this client. configure(DORA_CONFIGS[13], *client.getServer()); diff --git a/src/bin/dhcp6/dhcp6_lexer.ll b/src/bin/dhcp6/dhcp6_lexer.ll index 8a2ec54a9d..bec1b90aee 100644 --- a/src/bin/dhcp6/dhcp6_lexer.ll +++ b/src/bin/dhcp6/dhcp6_lexer.ll @@ -1258,39 +1258,6 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu] } } -\"reservations-out-of-pool\" { - switch(driver.ctx_) { - case isc::dhcp::Parser6Context::DHCP6: - case isc::dhcp::Parser6Context::SUBNET6: - case isc::dhcp::Parser6Context::SHARED_NETWORK: - return isc::dhcp::Dhcp6Parser::make_RESERVATIONS_OUT_OF_POOL(driver.loc_); - default: - return isc::dhcp::Dhcp6Parser::make_STRING("reservations-out-of-pool", driver.loc_); - } -} - -\"reservations-in-subnet\" { - switch(driver.ctx_) { - case isc::dhcp::Parser6Context::DHCP6: - case isc::dhcp::Parser6Context::SUBNET6: - case isc::dhcp::Parser6Context::SHARED_NETWORK: - return isc::dhcp::Dhcp6Parser::make_RESERVATIONS_IN_SUBNET(driver.loc_); - default: - return isc::dhcp::Dhcp6Parser::make_STRING("reservations-in-subnet", driver.loc_); - } -} - -\"reservations-global\" { - switch(driver.ctx_) { - case isc::dhcp::Parser6Context::DHCP6: - case isc::dhcp::Parser6Context::SUBNET6: - case isc::dhcp::Parser6Context::SHARED_NETWORK: - return isc::dhcp::Dhcp6Parser::make_RESERVATIONS_GLOBAL(driver.loc_); - default: - return isc::dhcp::Dhcp6Parser::make_STRING("reservations-global", driver.loc_); - } -} - \"reservation-mode\" { switch(driver.ctx_) { case isc::dhcp::Parser6Context::DHCP6: @@ -1347,6 +1314,39 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu] } } +\"reservations-global\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + case isc::dhcp::Parser6Context::SUBNET6: + case isc::dhcp::Parser6Context::SHARED_NETWORK: + return isc::dhcp::Dhcp6Parser::make_RESERVATIONS_GLOBAL(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("reservations-global", driver.loc_); + } +} + +\"reservations-in-subnet\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + case isc::dhcp::Parser6Context::SUBNET6: + case isc::dhcp::Parser6Context::SHARED_NETWORK: + return isc::dhcp::Dhcp6Parser::make_RESERVATIONS_IN_SUBNET(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("reservations-in-subnet", driver.loc_); + } +} + +\"reservations-out-of-pool\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + case isc::dhcp::Parser6Context::SUBNET6: + case isc::dhcp::Parser6Context::SHARED_NETWORK: + return isc::dhcp::Dhcp6Parser::make_RESERVATIONS_OUT_OF_POOL(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("reservations-out-of-pool", driver.loc_); + } +} + \"code\" { switch(driver.ctx_) { case isc::dhcp::Parser6Context::OPTION_DEF: diff --git a/src/bin/dhcp6/dhcp6_parser.yy b/src/bin/dhcp6/dhcp6_parser.yy index bad71cb342..8bc41b3f49 100644 --- a/src/bin/dhcp6/dhcp6_parser.yy +++ b/src/bin/dhcp6/dhcp6_parser.yy @@ -145,13 +145,13 @@ using namespace std; ID "id" RAPID_COMMIT "rapid-commit" RESERVATION_MODE "reservation-mode" - RESERVATIONS_OUT_OF_POOL "reservations-out-of-pool" - RESERVATIONS_IN_SUBNET "reservations-in-subnet" - RESERVATIONS_GLOBAL "reservations-global" DISABLED "disabled" OUT_OF_POOL "out-of-pool" GLOBAL "global" ALL "all" + RESERVATIONS_GLOBAL "reservations-global" + RESERVATIONS_IN_SUBNET "reservations-in-subnet" + RESERVATIONS_OUT_OF_POOL "reservations-out-of-pool" MAC_SOURCES "mac-sources" RELAY_SUPPLIED_OPTIONS "relay-supplied-options" @@ -495,9 +495,9 @@ global_param: data_directory | config_control | server_tag | reservation_mode - | reservations_out_of_pool - | reservations_in_subnet | reservations_global + | reservations_in_subnet + | reservations_out_of_pool | calculate_tee_times | t1_percent | t2_percent @@ -1393,9 +1393,9 @@ subnet6_param: preferred_lifetime | require_client_classes | reservations | reservation_mode - | reservations_out_of_pool - | reservations_in_subnet | reservations_global + | reservations_in_subnet + | reservations_out_of_pool | relay | user_context | comment @@ -1465,10 +1465,10 @@ require_client_classes: REQUIRE_CLIENT_CLASSES { ctx.leave(); }; -reservations_out_of_pool: RESERVATIONS_OUT_OF_POOL COLON BOOLEAN { - ctx.unique("reservations-out-of-pool", ctx.loc2pos(@1)); +reservations_global: RESERVATIONS_GLOBAL COLON BOOLEAN { + ctx.unique("reservations-global", ctx.loc2pos(@1)); ElementPtr b(new BoolElement($3, ctx.loc2pos(@3))); - ctx.stack_.back()->set("reservations-out-of-pool", b); + ctx.stack_.back()->set("reservations-global", b); }; reservations_in_subnet: RESERVATIONS_IN_SUBNET COLON BOOLEAN { @@ -1477,10 +1477,10 @@ reservations_in_subnet: RESERVATIONS_IN_SUBNET COLON BOOLEAN { ctx.stack_.back()->set("reservations-in-subnet", b); }; -reservations_global: RESERVATIONS_GLOBAL COLON BOOLEAN { - ctx.unique("reservations-global", ctx.loc2pos(@1)); +reservations_out_of_pool: RESERVATIONS_OUT_OF_POOL COLON BOOLEAN { + ctx.unique("reservations-out-of-pool", ctx.loc2pos(@1)); ElementPtr b(new BoolElement($3, ctx.loc2pos(@3))); - ctx.stack_.back()->set("reservations-global", b); + ctx.stack_.back()->set("reservations-out-of-pool", b); }; reservation_mode: RESERVATION_MODE { @@ -1553,9 +1553,9 @@ shared_network_param: name | option_data_list | relay | reservation_mode - | reservations_out_of_pool - | reservations_in_subnet | reservations_global + | reservations_in_subnet + | reservations_out_of_pool | client_class | require_client_classes | preferred_lifetime diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index f28255ae9d..7544a52fac 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -3774,8 +3774,11 @@ Dhcpv6Srv::conditionallySetReservedClientClasses(const Pkt6Ptr& pkt, if (ctx.subnet_) { SharedNetwork6Ptr shared_network; ctx.subnet_->getSharedNetwork(shared_network); - if (shared_network && !ctx.globalHost()) { - setReservedClientClasses(pkt, ctx); + if (shared_network) { + ConstHostPtr host = ctx.currentHost(); + if (host && (host->getIPv6SubnetID() != SUBNET_ID_GLOBAL)) { + setReservedClientClasses(pkt, ctx); + } } } } diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc index 4477a56185..e631d5d49d 100644 --- a/src/bin/dhcp6/json_config_parser.cc +++ b/src/bin/dhcp6/json_config_parser.cc @@ -450,7 +450,12 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set, // Print the list of known backends. HostDataSourceFactory::printRegistered(); - // Answer will hold the result. + // This is a way to convert ConstElementPtr to ElementPtr. + // We need a config that can be edited, because we will insert + // default values and will insert derived values as well. + ElementPtr mutable_cfg = boost::const_pointer_cast(config_set); + + // answer will hold the result. ConstElementPtr answer; // Rollback informs whether error occurred and original data // have to be restored to global storages. @@ -468,53 +473,17 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set, // default values and will insert derived values as well. mutable_cfg = boost::const_pointer_cast(config_set); - bool found = false; - ConstElementPtr reservations_out_of_pool = mutable_cfg->get("reservations-out-of-pool"); - ConstElementPtr reservations_in_subnet = mutable_cfg->get("reservations-in-subnet"); - ConstElementPtr reservations_global = mutable_cfg->get("reservations-global"); - if (reservations_out_of_pool || reservations_in_subnet || reservations_global) { - found = true; - } - ConstElementPtr reservation_mode = mutable_cfg->get("reservation-mode"); - if (reservation_mode) { - LOG_WARN(dhcp6_logger, DHCP6_DEPRECATED_RESERVATION_MODE); - if (found) { - isc_throw(DhcpConfigError, "invalid use of both 'reservation-mode'" - " and one of 'reservations-out-of-pool'" - " , 'reservations-in-subnet' or" - " 'reservations-global' parameters"); - } - } - - // reset all other reservation flags to overwrite default values. - if (found) { - bool force_true = false; - if (!reservations_out_of_pool) { - mutable_cfg->set("reservations-out-of-pool", Element::create(false)); - } else { - force_true = reservations_out_of_pool->boolValue(); - } - if (!reservations_in_subnet) { - if (force_true) { - mutable_cfg->set("reservations-in-subnet", Element::create(true)); - } else { - mutable_cfg->set("reservations-in-subnet", Element::create(false)); - } - } else if (force_true && !reservations_in_subnet->boolValue()) { - isc_throw(DhcpConfigError, "invalid use of disabled 'reservations-in-subnet'" - " when enabled 'reservations-out-of-pool'"); - } - if (!reservations_global) { - mutable_cfg->set("reservations-global", Element::create(false)); - } - } - // Relocate dhcp-ddns parameters that have moved to global scope. // Rule is that a global value overrides the dhcp-ddns value, so // we need to do this before we apply global defaults. // Note this is done for backward compatibility. srv_config->moveDdnsParams(mutable_cfg); + // Move from reservation mode to new reservations flags. + if (BaseNetworkParser::moveReservationMode(mutable_cfg)) { + LOG_WARN(dhcp6_logger, DHCP6_DEPRECATED_RESERVATION_MODE); + } + // Set all default values if not specified by the user. SimpleParser6::setAllDefaults(mutable_cfg); @@ -533,14 +502,6 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set, // Apply global options in the staging config, e.g. ip-reservations-unique global_parser.parseEarly(srv_config, mutable_cfg); - // If using deprecated reservation-mode, remove defaults for new parameters - // reservations-out-of-pool, reservations-in-subnet and reservations-global. - if (reservation_mode) { - mutable_cfg->remove("reservations-out-of-pool"); - mutable_cfg->remove("reservations-in-subnet"); - mutable_cfg->remove("reservations-global"); - } - // Specific check for this global parameter. ConstElementPtr data_directory = mutable_cfg->get("data-directory"); if (data_directory) { @@ -810,9 +771,9 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set, (config_pair.first == "dhcp4o6-port") || (config_pair.first == "server-tag") || (config_pair.first == "reservation-mode") || - (config_pair.first == "reservations-out-of-pool") || - (config_pair.first == "reservations-in-subnet") || (config_pair.first == "reservations-global") || + (config_pair.first == "reservations-in-subnet") || + (config_pair.first == "reservations-out-of-pool") || (config_pair.first == "calculate-tee-times") || (config_pair.first == "t1-percent") || (config_pair.first == "t2-percent") || diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index 18e0c681dc..bfe1fc2ab9 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -5649,99 +5649,10 @@ TEST_F(Dhcp6ParserTest, macSourcesBogus) { checkResult(status, 1); } -/// The goal of this test is to verify that Host Reservation modes can be +/// The goal of this test is to verify that Host Reservation flags can be /// specified on a per-subnet basis. TEST_F(Dhcp6ParserTest, hostReservationPerSubnet) { - /// - Configuration: - /// - only addresses (no prefixes) - /// - 5 subnets with: - /// - 2001:db8:1::/64 (all reservations enabled) - /// - 2001:db8:2::/64 (out-of-pool reservations) - /// - 2001:db8:3::/64 (reservations disabled) - /// - 2001:db8:4::/64 (global reservations) - /// - 2001:db8:5::/64 (reservations not specified) - const char* hr_config = - "{" - "\"preferred-lifetime\": 3000," - "\"rebind-timer\": 2000, " - "\"renew-timer\": 1000, " - "\"subnet6\": [ { " - " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ]," - " \"subnet\": \"2001:db8:1::/48\", " - " \"reservation-mode\": \"all\"" - " }," - " {" - " \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ]," - " \"subnet\": \"2001:db8:2::/48\", " - " \"reservation-mode\": \"out-of-pool\"" - " }," - " {" - " \"pools\": [ { \"pool\": \"2001:db8:3::/64\" } ]," - " \"subnet\": \"2001:db8:3::/48\", " - " \"reservation-mode\": \"disabled\"" - " }," - " {" - " \"pools\": [ { \"pool\": \"2001:db8:4::/64\" } ]," - " \"subnet\": \"2001:db8:4::/48\", " - " \"reservation-mode\": \"global\"" - " }," - " {" - " \"pools\": [ { \"pool\": \"2001:db8:5::/64\" } ]," - " \"subnet\": \"2001:db8:5::/48\" " - " } ]," - "\"valid-lifetime\": 4000 }"; - - ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP6(hr_config)); - extractConfig(hr_config); - - ConstElementPtr status; - EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json)); - - // returned value should be 0 (success) - checkResult(status, 0); - CfgMgr::instance().commit(); - - // Let's get all subnets and check that there are 5 of them. - ConstCfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6(); - ASSERT_TRUE(subnets); - const Subnet6Collection* subnet_col = subnets->getAll(); - ASSERT_EQ(5, subnet_col->size()); // We expect 5 subnets - - // Let's check if the parsed subnets have correct HR modes. - - // Subnet 1 - Subnet6Ptr subnet; - subnet = subnets->selectSubnet(IOAddress("2001:db8:1::1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); - - // Subnet 2 - subnet = subnets->selectSubnet(IOAddress("2001:db8:2::1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode()); - - // Subnet 3 - subnet = subnets->selectSubnet(IOAddress("2001:db8:3::1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_DISABLED, subnet->getHostReservationMode()); - - // Subnet 4 - subnet = subnets->selectSubnet(IOAddress("2001:db8:4::1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_GLOBAL, subnet->getHostReservationMode()); - - // Subnet 5 - subnet = subnets->selectSubnet(IOAddress("2001:db8:5::1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); -} - -/// The goal of this test is to verify that Host Reservation modes can be -/// specified on a per-subnet basis. -TEST_F(Dhcp6ParserTest, hostReservationModesPerSubnet) { - /// - Configuration: /// - only addresses (no prefixes) /// - 7 subnets with: @@ -5760,24 +5671,30 @@ TEST_F(Dhcp6ParserTest, hostReservationModesPerSubnet) { "\"subnet6\": [ { " " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ]," " \"subnet\": \"2001:db8:1::/48\", " - " \"reservations-in-subnet\": true" + " \"reservations-global\": false," + " \"reservations-in-subnet\": true," + " \"reservations-out-of-pool\": false" " }," " {" " \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ]," " \"subnet\": \"2001:db8:2::/48\", " + " \"reservations-global\": false," + " \"reservations-in-subnet\": true," " \"reservations-out-of-pool\": true" " }," " {" " \"pools\": [ { \"pool\": \"2001:db8:3::/64\" } ]," " \"subnet\": \"2001:db8:3::/48\", " - " \"reservations-out-of-pool\": false," + " \"reservations-global\": false," " \"reservations-in-subnet\": false," - " \"reservations-global\": false" + " \"reservations-out-of-pool\": false" " }," " {" " \"pools\": [ { \"pool\": \"2001:db8:4::/64\" } ]," " \"subnet\": \"2001:db8:4::/48\", " - " \"reservations-global\": true" + " \"reservations-global\": true," + " \"reservations-in-subnet\": false," + " \"reservations-out-of-pool\": false" " }," " {" " \"pools\": [ { \"pool\": \"2001:db8:5::/64\" } ]," @@ -5786,16 +5703,16 @@ TEST_F(Dhcp6ParserTest, hostReservationModesPerSubnet) { " {" " \"pools\": [ { \"pool\": \"2001:db8:6::/64\" } ]," " \"subnet\": \"2001:db8:6::/48\", " - " \"reservations-out-of-pool\": false," + " \"reservations-global\": true," " \"reservations-in-subnet\": true," - " \"reservations-global\": true" + " \"reservations-out-of-pool\": false" " }," " {" " \"pools\": [ { \"pool\": \"2001:db8:7::/64\" } ]," " \"subnet\": \"2001:db8:7::/48\", " - " \"reservations-out-of-pool\": true," + " \"reservations-global\": true," " \"reservations-in-subnet\": true," - " \"reservations-global\": true" + " \"reservations-out-of-pool\": true" " } ]," "\"valid-lifetime\": 4000 }"; @@ -5822,41 +5739,55 @@ TEST_F(Dhcp6ParserTest, hostReservationModesPerSubnet) { Subnet6Ptr subnet; subnet = subnets->selectSubnet(IOAddress("2001:db8:1::1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 2 subnet = subnets->selectSubnet(IOAddress("2001:db8:2::1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_TRUE(subnet->getReservationsOutOfPool()); // Subnet 3 subnet = subnets->selectSubnet(IOAddress("2001:db8:3::1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_DISABLED, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_FALSE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 4 subnet = subnets->selectSubnet(IOAddress("2001:db8:4::1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_GLOBAL, subnet->getHostReservationMode()); + EXPECT_TRUE(subnet->getReservationsGlobal()); + EXPECT_FALSE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 5 subnet = subnets->selectSubnet(IOAddress("2001:db8:5::1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 6 subnet = subnets->selectSubnet(IOAddress("2001:db8:6::1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL|Network::HR_GLOBAL, subnet->getHostReservationMode()); + EXPECT_TRUE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 7 subnet = subnets->selectSubnet(IOAddress("2001:db8:7::1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_OUT_OF_POOL|Network::HR_GLOBAL, - subnet->getHostReservationMode()); + EXPECT_TRUE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_TRUE(subnet->getReservationsOutOfPool()); + } -/// The goal of this test is to verify that Host Reservation modes can be +/// The goal of this test is to verify that Host Reservation flags can be /// specified globally. TEST_F(Dhcp6ParserTest, hostReservationGlobal) { @@ -5870,68 +5801,15 @@ TEST_F(Dhcp6ParserTest, hostReservationGlobal) { "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " - "\"reservation-mode\": \"out-of-pool\", " - "\"subnet6\": [ { " - " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ]," - " \"subnet\": \"2001:db8:1::/48\", " - " \"reservation-mode\": \"all\"" - " }," - " {" - " \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ]," - " \"subnet\": \"2001:db8:2::/48\" " - " } ]," - "\"valid-lifetime\": 4000 }"; - - ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP6(hr_config)); - extractConfig(hr_config); - - ConstElementPtr status; - EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json)); - - // returned value should be 0 (success) - checkResult(status, 0); - CfgMgr::instance().commit(); - - // Let's get all subnets and check that there are 2 of them. - ConstCfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6(); - ASSERT_TRUE(subnets); - const Subnet6Collection* subnet_col = subnets->getAll(); - ASSERT_EQ(2, subnet_col->size()); // We expect 2 subnets - - // Let's check if the parsed subnets have correct HR modes. - - // Subnet 1 - Subnet6Ptr subnet; - subnet = subnets->selectSubnet(IOAddress("2001:db8:1::1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); - - // Subnet 2 - subnet = subnets->selectSubnet(IOAddress("2001:db8:2::1")); - ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode()); -} - -/// The goal of this test is to verify that Host Reservation modes can be -/// specified globally. -TEST_F(Dhcp6ParserTest, hostReservationModesGlobal) { - - /// - Configuration: - /// - only addresses (no prefixes) - /// - 2 subnets with: - /// - 2001:db8:1::/64 (all reservations enabled) - /// - 2001:db8:2::/64 (reservations not specified) - const char* hr_config = - "{" - "\"preferred-lifetime\": 3000," - "\"rebind-timer\": 2000, " - "\"renew-timer\": 1000, " + "\"reservations-global\": false," + "\"reservations-in-subnet\": true," "\"reservations-out-of-pool\": true," "\"subnet6\": [ { " " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ]," " \"subnet\": \"2001:db8:1::/48\", " - " \"reservations-in-subnet\": true" + " \"reservations-global\": false," + " \"reservations-in-subnet\": true," + " \"reservations-out-of-pool\": false" " }," " {" " \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ]," @@ -5962,12 +5840,16 @@ TEST_F(Dhcp6ParserTest, hostReservationModesGlobal) { Subnet6Ptr subnet; subnet = subnets->selectSubnet(IOAddress("2001:db8:1::1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_FALSE(subnet->getReservationsOutOfPool()); // Subnet 2 subnet = subnets->selectSubnet(IOAddress("2001:db8:2::1")); ASSERT_TRUE(subnet); - EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode()); + EXPECT_FALSE(subnet->getReservationsGlobal()); + EXPECT_TRUE(subnet->getReservationsInSubnet()); + EXPECT_TRUE(subnet->getReservationsOutOfPool()); } /// The goal of this test is to verify that configuration can include @@ -6889,7 +6771,9 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { " \"ip-address\": \"1111::1\"\n" " },\n" " \"rapid-commit\": true,\n" - " \"reservations-global\": false," + " \"reservations-global\": false,\n" + " \"reservations-in-subnet\": false,\n" + " \"reservations-out-of-pool\": false,\n" " \"subnet6\": [\n" " { \n" " \"subnet\": \"2001:db1::/48\",\n" @@ -6911,7 +6795,9 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { " \"max-valid-lifetime\": 500, \n" " \"interface-id\": \"twotwo\",\n" " \"rapid-commit\": true,\n" - " \"reservations-out-of-pool\": true" + " \"reservations-global\": false,\n" + " \"reservations-in-subnet\": true,\n" + " \"reservations-out-of-pool\": true\n" " }\n" " ]\n" " },\n" @@ -6957,7 +6843,9 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { EXPECT_TRUE(iface_id1.equals(s->getInterfaceId())); EXPECT_TRUE(s->hasRelayAddress(IOAddress("1111::1"))); EXPECT_TRUE(s->getRapidCommit()); - EXPECT_EQ(Network::HR_DISABLED, s->getHostReservationMode()); + EXPECT_FALSE(s->getReservationsGlobal()); + EXPECT_FALSE(s->getReservationsInSubnet()); + EXPECT_FALSE(s->getReservationsOutOfPool()); EXPECT_TRUE(s->getStoreExtendedInfo()); // For the second subnet, the renew-timer should be 100, because it @@ -6970,7 +6858,9 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { EXPECT_TRUE(iface_id2.equals(s->getInterfaceId())); EXPECT_TRUE(s->hasRelayAddress(IOAddress("2222::2"))); EXPECT_TRUE(s->getRapidCommit()); - EXPECT_EQ(Network::HR_OUT_OF_POOL, s->getHostReservationMode()); + EXPECT_FALSE(s->getReservationsGlobal()); + EXPECT_TRUE(s->getReservationsInSubnet()); + EXPECT_TRUE(s->getReservationsOutOfPool()); EXPECT_TRUE(s->getStoreExtendedInfo()); // Ok, now check the second shared subnet. @@ -6986,7 +6876,9 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { EXPECT_FALSE(s->getInterfaceId()); EXPECT_FALSE(s->hasRelays()); EXPECT_FALSE(s->getRapidCommit()); - EXPECT_EQ(Network::HR_ALL, s->getHostReservationMode()); + EXPECT_FALSE(s->getReservationsGlobal()); + EXPECT_TRUE(s->getReservationsInSubnet()); + EXPECT_FALSE(s->getReservationsOutOfPool()); EXPECT_FALSE(s->getStoreExtendedInfo()); } diff --git a/src/bin/dhcp6/tests/sarr_unittest.cc b/src/bin/dhcp6/tests/sarr_unittest.cc index 080b23524d..f6572b62e6 100644 --- a/src/bin/dhcp6/tests/sarr_unittest.cc +++ b/src/bin/dhcp6/tests/sarr_unittest.cc @@ -194,7 +194,9 @@ const char* CONFIGS[] = { " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::10\" } ]," " \"subnet\": \"2001:db8:1::/48\", " " \"interface\": \"eth0\", " - " \"reservation-mode\": \"out-of-pool\"," + " \"reservations-global\": false," + " \"reservations-in-subnet\": true," + " \"reservations-out-of-pool\": true," " \"reservations\": [ " " {" " \"duid\": \"aa:bb:cc:dd:ee:ff\"," diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc index 8aa9be944b..df1609a66a 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc @@ -267,7 +267,7 @@ public: MySqlBinding::createString(RELAY_BUF_LENGTH), // relay MySqlBinding::createInteger(), // renew_timer MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // require_client_classes - MySqlBinding::createInteger(), // reservation_mode + MySqlBinding::createInteger(), // reservations_global MySqlBinding::createString(SERVER_HOSTNAME_BUF_LENGTH), // server_hostname MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // shared_network_name MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context @@ -316,6 +316,8 @@ public: MySqlBinding::createInteger(), // ddns_replace_client_name MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_generated_prefix MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_qualifying_suffix + MySqlBinding::createInteger(), // reservations_in_subnet + MySqlBinding::createInteger(), // reservations_out_of_pool MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag }; @@ -353,13 +355,17 @@ public: // subnet_id SubnetID subnet_id(out_bindings[0]->getInteger()); + // subnet_prefix std::string subnet_prefix = out_bindings[1]->getString(); auto prefix_pair = Subnet4::parsePrefix(subnet_prefix); + // renew_timer auto renew_timer = createTriplet(out_bindings[13]); + // rebind_timer auto rebind_timer = createTriplet(out_bindings[11]); + // valid_lifetime (and {min,max)_valid_lifetime) auto valid_lifetime = createTriplet(out_bindings[19], out_bindings[53], @@ -374,6 +380,7 @@ public: if (!out_bindings[2]->amNull()) { last_subnet->get4o6().setIface4o6(out_bindings[2]->getString()); } + // 4o6_interface_id if (!out_bindings[3]->amNull()) { std::string dhcp4o6_interface_id = out_bindings[3]->getString(); @@ -383,6 +390,7 @@ public: Option::create(Option::V6, D6O_INTERFACE_ID, dhcp4o6_interface_id_buf); last_subnet->get4o6().setInterfaceId(option_dhcp4o6_interface_id); } + // 4o6_subnet if (!out_bindings[4]->amNull()) { std::pair dhcp4o6_subnet_prefix_pair = @@ -390,6 +398,7 @@ public: last_subnet->get4o6().setSubnet4o6(dhcp4o6_subnet_prefix_pair.first, dhcp4o6_subnet_prefix_pair.second); } + // boot_file_name if (!out_bindings[5]->amNull()) { last_subnet->setFilename(out_bindings[5]->getString()); @@ -399,6 +408,7 @@ public: if (!out_bindings[6]->amNull()) { last_subnet->allowClientClass(out_bindings[6]->getString()); } + // interface if (!out_bindings[7]->amNull()) { last_subnet->setIface(out_bindings[7]->getString()); @@ -450,10 +460,9 @@ public: } } - // reservation_mode + // reservations_global if (!out_bindings[15]->amNull()) { - last_subnet->setHostReservationMode(static_cast - (out_bindings[15]->getInteger())); + last_subnet->setReservationsGlobal(out_bindings[15]->getBool()); } // server_hostname @@ -492,42 +501,46 @@ public: last_subnet->setAuthoritative(out_bindings[52]->getBool()); } - // {min,max}_valid_lifetime - - // pool client_class, require_client_classes and user_context - - // ddns_send_updates at 58 + // ddns_send_updates if (!out_bindings[58]->amNull()) { last_subnet->setDdnsSendUpdates(out_bindings[58]->getBool()); } - // ddns_override_no_update at 59 + // ddns_override_no_update if (!out_bindings[59]->amNull()) { last_subnet->setDdnsOverrideNoUpdate(out_bindings[59]->getBool()); } - // ddns_override_client_update at 60 + // ddns_override_client_update if (!out_bindings[60]->amNull()) { last_subnet->setDdnsOverrideClientUpdate(out_bindings[60]->getBool()); } - // ddns_replace_client_name at 61 + // ddns_replace_client_name if (!out_bindings[61]->amNull()) { last_subnet->setDdnsReplaceClientNameMode(static_cast (out_bindings[61]->getInteger())); } - // ddns_generated_prefix at 62 + // ddns_generated_prefix if (!out_bindings[62]->amNull()) { last_subnet->setDdnsGeneratedPrefix(out_bindings[62]->getString()); } - // ddns_qualifying_suffix at 63 + // ddns_qualifying_suffix if (!out_bindings[63]->amNull()) { last_subnet->setDdnsQualifyingSuffix(out_bindings[63]->getString()); } - // server_tag at 64 + // reservations_in_subnet + if (!out_bindings[64]->amNull()) { + last_subnet->setReservationsInSubnet(out_bindings[64]->getBool()); + } + + // reservations_out_of_pool + if (!out_bindings[65]->amNull()) { + last_subnet->setReservationsOutOfPool(out_bindings[65]->getBool()); + } // Subnet ready. Add it to the list. auto ret = subnets.insert(last_subnet); @@ -541,14 +554,16 @@ public: } // Check for new server tags. - if (!out_bindings[64]->amNull() && - (last_tag != out_bindings[64]->getString())) { - last_tag = out_bindings[64]->getString(); + if (!out_bindings[66]->amNull() && + (last_tag != out_bindings[66]->getString())) { + last_tag = out_bindings[66]->getString(); if (!last_tag.empty() && !last_subnet->hasServerTag(ServerTag(last_tag))) { last_subnet->setServerTag(last_tag); } } + // Pool is between 20 and 25 with extra between 55 and 57 + // If the row contains information about the pool and it appears to be // new pool entry (checked by comparing pool id), let's create the new // pool and add it to the subnet. @@ -591,7 +606,7 @@ public: last_subnet->addPool(last_pool); } - // Parse pool specific option. + // Parse pool specific option between 25 and 36 if (last_pool && !out_bindings[25]->amNull() && (last_pool_option_id < out_bindings[25]->getInteger())) { last_pool_option_id = out_bindings[25]->getInteger(); @@ -602,7 +617,7 @@ public: } } - // Parse subnet specific option. + // Parse subnet specific option between 37 and 48 if (!out_bindings[37]->amNull() && (last_option_id < out_bindings[37]->getInteger())) { last_option_id = out_bindings[37]->getInteger(); @@ -797,12 +812,12 @@ public: last_pool = Pool4::create(IOAddress(out_bindings[1]->getInteger()), IOAddress(out_bindings[2]->getInteger())); - // pool client_class (4) + // pool client_class if (!out_bindings[4]->amNull()) { last_pool->allowClientClass(out_bindings[4]->getString()); } - // pool require_client_classes (5) + // pool require_client_classes ElementPtr require_element = out_bindings[5]->getJSON(); if (require_element) { if (require_element->getType() != Element::list) { @@ -819,19 +834,17 @@ public: } } - // pool user_context (6) + // pool user_context ElementPtr user_context = out_bindings[6]->getJSON(); if (user_context) { last_pool->setContext(user_context); } - // pool: modification_ts (7) - pools.push_back(last_pool); pool_ids.push_back(last_pool_id); } - // Parse pool specific option (8). + // Parse pool specific option between 8 and 19 if (last_pool && !out_bindings[8]->amNull() && (last_pool_option_id < out_bindings[8]->getInteger())) { last_pool_option_id = out_bindings[8]->getInteger(); @@ -937,16 +950,6 @@ public: required_classes_element->add(Element::create(*required_class)); } - // Create binding for host reservation mode. - MySqlBindingPtr hr_mode_binding; - auto hr_mode = subnet->getHostReservationMode(Network::Inheritance::NONE); - if (!hr_mode.unspecified()) { - hr_mode_binding = MySqlBinding::createInteger(static_cast - (hr_mode.get())); - } else { - hr_mode_binding = MySqlBinding::createNull(); - } - // Create binding for DDNS replace client name mode. MySqlBindingPtr ddns_rcn_mode_binding; auto ddns_rcn_mode = subnet->getDdnsReplaceClientNameMode(Network::Inheritance::NONE); @@ -1001,7 +1004,7 @@ public: createInputRelayBinding(subnet), createBinding(subnet->getT1(Network::Inheritance::NONE)), createInputRequiredClassesBinding(subnet), - hr_mode_binding, + MySqlBinding::condCreateBool(subnet->getReservationsGlobal(Network::Inheritance::NONE)), MySqlBinding::condCreateString(subnet->getSname(Network::Inheritance::NONE)), shared_network_binding, createInputContextBinding(subnet), @@ -1017,7 +1020,9 @@ public: MySqlBinding::condCreateBool(subnet->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)), ddns_rcn_mode_binding, MySqlBinding::condCreateString(subnet->getDdnsGeneratedPrefix(Network::Inheritance::NONE)), - MySqlBinding::condCreateString(subnet->getDdnsQualifyingSuffix(Network::Inheritance::NONE)) + MySqlBinding::condCreateString(subnet->getDdnsQualifyingSuffix(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getReservationsInSubnet(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getReservationsOutOfPool(Network::Inheritance::NONE)) }; MySqlTransaction transaction(conn_); @@ -1231,7 +1236,7 @@ public: MySqlBinding::createString(RELAY_BUF_LENGTH), // relay MySqlBinding::createInteger(), // renew_timer MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // require_client_classes - MySqlBinding::createInteger(), // reservation_mode + MySqlBinding::createInteger(), // reservations_global MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context MySqlBinding::createInteger(), // valid_lifetime MySqlBinding::createInteger(), // option: option_id @@ -1261,6 +1266,8 @@ public: MySqlBinding::createInteger(), // ddns_replace_client_name MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_generated_prefix MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_qualifying_suffix + MySqlBinding::createInteger(), // reservations_in_subnet + MySqlBinding::createInteger(), // reservations_out_of_pool MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag }; @@ -1352,10 +1359,9 @@ public: } } - // reservation_mode + // reservations_global if (!out_bindings[10]->amNull()) { - last_network->setHostReservationMode(static_cast - (out_bindings[10]->getIntegerOrDefault(Network::HR_ALL))); + last_network->setReservationsGlobal(out_bindings[10]->getBool()); } // user_context @@ -1408,37 +1414,47 @@ public: // {min,max}_valid_lifetime - // ddns_send_updates at 34 + // ddns_send_updates if (!out_bindings[34]->amNull()) { last_network->setDdnsSendUpdates(out_bindings[34]->getBool()); } - // ddns_override_no_update at 35 + // ddns_override_no_update if (!out_bindings[35]->amNull()) { last_network->setDdnsOverrideNoUpdate(out_bindings[35]->getBool()); } - // ddns_override_client_update at 36 + // ddns_override_client_update if (!out_bindings[36]->amNull()) { last_network->setDdnsOverrideClientUpdate(out_bindings[36]->getBool()); } - // ddns_replace_client_name at 37 + // ddns_replace_client_name if (!out_bindings[37]->amNull()) { last_network->setDdnsReplaceClientNameMode(static_cast (out_bindings[37]->getInteger())); } - // ddns_generated_prefix at 38 + // ddns_generated_prefix if (!out_bindings[38]->amNull()) { last_network->setDdnsGeneratedPrefix(out_bindings[38]->getString()); } - // ddns_qualifying_suffix at 39 + // ddns_qualifying_suffix if (!out_bindings[39]->amNull()) { last_network->setDdnsQualifyingSuffix(out_bindings[39]->getString()); } + // reservations_in_subnet + if (!out_bindings[40]->amNull()) { + last_network->setReservationsInSubnet(out_bindings[40]->getBool()); + } + + // reservations_out_of_pool + if (!out_bindings[41]->amNull()) { + last_network->setReservationsOutOfPool(out_bindings[41]->getBool()); + } + // Add the shared network. auto ret = shared_networks.push_back(last_network); @@ -1451,15 +1467,15 @@ public: } // Check for new server tags. - if (!out_bindings[40]->amNull() && - (last_tag != out_bindings[40]->getString())) { - last_tag = out_bindings[40]->getString(); + if (!out_bindings[42]->amNull() && + (last_tag != out_bindings[42]->getString())) { + last_tag = out_bindings[42]->getString(); if (!last_tag.empty() && !last_network->hasServerTag(ServerTag(last_tag))) { last_network->setServerTag(last_tag); } } - // Parse option. + // Parse option from 13 to 24 if (!out_bindings[13]->amNull() && (last_option_id < out_bindings[13]->getInteger())) { last_option_id = out_bindings[13]->getInteger(); @@ -1569,16 +1585,6 @@ public: " assigning it to a server or all servers is not supported"); } - // Create binding for host reservation mode. - MySqlBindingPtr hr_mode_binding; - auto hr_mode = shared_network->getHostReservationMode(Network::Inheritance::NONE); - if (!hr_mode.unspecified()) { - hr_mode_binding = MySqlBinding::createInteger(static_cast - (hr_mode.get())); - } else { - hr_mode_binding = MySqlBinding::createNull(); - } - // Create binding for DDNS replace client name mode. MySqlBindingPtr ddns_rcn_mode_binding; auto ddns_rcn_mode = shared_network->getDdnsReplaceClientNameMode(Network::Inheritance::NONE); @@ -1599,7 +1605,7 @@ public: createInputRelayBinding(shared_network), createBinding(shared_network->getT1(Network::Inheritance::NONE)), createInputRequiredClassesBinding(shared_network), - hr_mode_binding, + MySqlBinding::condCreateBool(shared_network->getReservationsGlobal(Network::Inheritance::NONE)), createInputContextBinding(shared_network), createBinding(shared_network->getValid(Network::Inheritance::NONE)), createMinBinding(shared_network->getValid(Network::Inheritance::NONE)), @@ -1616,7 +1622,9 @@ public: MySqlBinding::condCreateBool(shared_network->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)), ddns_rcn_mode_binding, MySqlBinding::condCreateString(shared_network->getDdnsGeneratedPrefix(Network::Inheritance::NONE)), - MySqlBinding::condCreateString(shared_network->getDdnsQualifyingSuffix(Network::Inheritance::NONE)) + MySqlBinding::condCreateString(shared_network->getDdnsQualifyingSuffix(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getReservationsInSubnet(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getReservationsOutOfPool(Network::Inheritance::NONE)) }; MySqlTransaction transaction(conn_); @@ -2448,7 +2456,7 @@ TaggedStatementArray tagged_statements = { { " relay," " renew_timer," " require_client_classes," - " reservation_mode," + " reservations_global," " server_hostname," " shared_network_name," " user_context," @@ -2464,9 +2472,11 @@ TaggedStatementArray tagged_statements = { { " ddns_override_client_update," " ddns_replace_client_name," " ddns_generated_prefix," - " ddns_qualifying_suffix" + " ddns_qualifying_suffix," + " reservations_in_subnet," + " reservations_out_of_pool" ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," - "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, // Insert association of the subnet with a server. { MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4_SERVER, @@ -2490,7 +2500,7 @@ TaggedStatementArray tagged_statements = { { " relay," " renew_timer," " require_client_classes," - " reservation_mode," + " reservations_global," " user_context," " valid_lifetime," " min_valid_lifetime," @@ -2507,9 +2517,11 @@ TaggedStatementArray tagged_statements = { { " ddns_override_client_update," " ddns_replace_client_name," " ddns_generated_prefix," - " ddns_qualifying_suffix" + " ddns_qualifying_suffix," + " reservations_in_subnet," + " reservations_out_of_pool" ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," - " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, + " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, // Insert association of the shared network with a server. { MySqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4_SERVER, @@ -2564,7 +2576,7 @@ TaggedStatementArray tagged_statements = { { " relay = ?," " renew_timer = ?," " require_client_classes = ?," - " reservation_mode = ?," + " reservations_global = ?," " server_hostname = ?," " shared_network_name = ?," " user_context = ?," @@ -2580,7 +2592,9 @@ TaggedStatementArray tagged_statements = { { " ddns_override_client_update = ?," " ddns_replace_client_name = ?," " ddns_generated_prefix = ?," - " ddns_qualifying_suffix = ? " + " ddns_qualifying_suffix = ?," + " reservations_in_subnet = ?," + " reservations_out_of_pool = ? " "WHERE subnet_id = ? OR subnet_prefix = ?" }, // Update existing shared network. @@ -2595,7 +2609,7 @@ TaggedStatementArray tagged_statements = { { " relay = ?," " renew_timer = ?," " require_client_classes = ?," - " reservation_mode = ?," + " reservations_global = ?," " user_context = ?," " valid_lifetime = ?," " min_valid_lifetime = ?," @@ -2612,7 +2626,9 @@ TaggedStatementArray tagged_statements = { { " ddns_override_client_update = ?," " ddns_replace_client_name = ?," " ddns_generated_prefix = ?," - " ddns_qualifying_suffix = ? " + " ddns_qualifying_suffix = ?," + " reservations_in_subnet = ?," + " reservations_out_of_pool = ? " "WHERE name = ?" }, // Update existing option definition. diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc index 6843d5ecde..207d5bb12f 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc @@ -274,7 +274,7 @@ public: MySqlBinding::createString(RELAY_BUF_LENGTH), // relay MySqlBinding::createInteger(), // renew_timer MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // require_client_classes - MySqlBinding::createInteger(), // reservation_mode + MySqlBinding::createInteger(), // reservations_global MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // shared_network_name MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context MySqlBinding::createInteger(), // valid_lifetime @@ -350,6 +350,8 @@ public: MySqlBinding::createInteger(), // ddns_replace_client_name MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_generated_prefix MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_qualifying_suffix + MySqlBinding::createInteger(), // reservations_in_subnet + MySqlBinding::createInteger(), // reservations_out_of_pool MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag }; @@ -392,10 +394,10 @@ public: last_pd_pool.reset(); last_tag.clear(); - // subnet_id (0) + // subnet_id SubnetID subnet_id(out_bindings[0]->getInteger()); - // subnet_prefix (1) + // subnet_prefix std::string subnet_prefix = out_bindings[1]->getString(); auto prefix_pair = Subnet6::parsePrefix(subnet_prefix); @@ -404,10 +406,10 @@ public: out_bindings[69], out_bindings[70]); - // renew_timer (9) + // renew_timer auto renew_timer = createTriplet(out_bindings[9]); - // rebind_timer (7) + // rebind_timer auto rebind_timer = createTriplet(out_bindings[7]); // valid_lifetime (and {min,max)_valid_lifetime) @@ -421,28 +423,25 @@ public: preferred_lifetime, valid_lifetime, subnet_id); - // client_class (2) + // client_class if (!out_bindings[2]->amNull()) { last_subnet->allowClientClass(out_bindings[2]->getString()); } - // interface (3) + // interface if (!out_bindings[3]->amNull()) { last_subnet->setIface(out_bindings[3]->getString()); } - // modification_ts (4) + // modification_ts last_subnet->setModificationTime(out_bindings[4]->getTimestamp()); - // 5 is preferred_lifetime - // rapid_commit (6) + // rapid_commit if (!out_bindings[6]->amNull()) { last_subnet->setRapidCommit(out_bindings[6]->getBool()); } - // 7 is rebind_timer - - // relay (8) + // relay ElementPtr relay_element = out_bindings[8]->getJSON(); if (relay_element) { if (relay_element->getType() != Element::list) { @@ -458,9 +457,7 @@ public: } } - // 9 is renew_timer - - // require_client_classes (10) + // require_client_classes ElementPtr require_element = out_bindings[10]->getJSON(); if (require_element) { if (require_element->getType() != Element::list) { @@ -477,41 +474,38 @@ public: } } - // reservation_mode (11) + // reservations_global if (!out_bindings[11]->amNull()) { - last_subnet->setHostReservationMode(static_cast - (out_bindings[11]->getInteger())); + last_subnet->setReservationsGlobal(out_bindings[11]->getBool()); } - // shared_network_name (12) + // shared_network_name if (!out_bindings[12]->amNull()) { last_subnet->setSharedNetworkName(out_bindings[12]->getString()); } - // user_context (13) + // user_context ElementPtr user_context = out_bindings[13]->getJSON(); if (user_context) { last_subnet->setContext(user_context); } - // 14 is valid_lifetime - - // calculate_tee_times (65) + // calculate_tee_times if (!out_bindings[65]->amNull()) { last_subnet->setCalculateTeeTimes(out_bindings[65]->getBool()); } - // t1_percent (66) + // t1_percent if (!out_bindings[66]->amNull()) { last_subnet->setT1Percent(out_bindings[66]->getFloat()); } - // t2_percent (67) + // t2_percent if (!out_bindings[67]->amNull()) { last_subnet->setT2Percent(out_bindings[67]->getFloat()); } - // interface_id (68) + // interface_id if (!out_bindings[68]->amNull()) { auto iface_id_data = out_bindings[68]->getBlob(); if (!iface_id_data.empty()) { @@ -521,51 +515,46 @@ 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 - - // ddns_send_updates (81) + // ddns_send_updates if (!out_bindings[81]->amNull()) { last_subnet->setDdnsSendUpdates(out_bindings[81]->getBool()); } - // ddns_override_no_update (82) + // ddns_override_no_update if (!out_bindings[82]->amNull()) { last_subnet->setDdnsOverrideNoUpdate(out_bindings[82]->getBool()); } - // ddns_override_client_update (83) + // ddns_override_client_update if (!out_bindings[83]->amNull()) { last_subnet->setDdnsOverrideClientUpdate(out_bindings[83]->getBool()); } - // ddns_replace_client_name (84) + // ddns_replace_client_name if (!out_bindings[84]->amNull()) { last_subnet->setDdnsReplaceClientNameMode(static_cast (out_bindings[84]->getInteger())); } - // ddns_generated_prefix (85) + // ddns_generated_prefix if (!out_bindings[85]->amNull()) { last_subnet->setDdnsGeneratedPrefix(out_bindings[85]->getString()); } - // ddns_qualifying_suffix (86) + // ddns_qualifying_suffix if (!out_bindings[86]->amNull()) { last_subnet->setDdnsQualifyingSuffix(out_bindings[86]->getString()); } - // server_tag (87 / last) + // reservations_in_subnet + if (!out_bindings[87]->amNull()) { + last_subnet->setReservationsInSubnet(out_bindings[87]->getBool()); + } + + // reservations_out_of_pool + if (!out_bindings[88]->amNull()) { + last_subnet->setReservationsOutOfPool(out_bindings[88]->getBool()); + } // Subnet ready. Add it to the list. auto ret = subnets.insert(last_subnet); @@ -579,9 +568,9 @@ public: } // Check for new server tags. - if (!out_bindings[87]->amNull() && - (last_tag != out_bindings[87]->getString())) { - last_tag = out_bindings[87]->getString(); + if (!out_bindings[89]->amNull() && + (last_tag != out_bindings[89]->getString())) { + last_tag = out_bindings[89]->getString(); if (!last_tag.empty() && !last_subnet->hasServerTag(ServerTag(last_tag))) { last_subnet->setServerTag(last_tag); } @@ -601,12 +590,12 @@ public: last_pool = Pool6::create(Lease::TYPE_NA, IOAddress(out_bindings[16]->getString()), IOAddress(out_bindings[17]->getString())); - // pool client_class (73) + // pool client_class if (!out_bindings[73]->amNull()) { last_pool->allowClientClass(out_bindings[73]->getString()); } - // pool require_client_classes (74) + // pool require_client_classes ElementPtr require_element = out_bindings[74]->getJSON(); if (require_element) { if (require_element->getType() != Element::list) { @@ -623,7 +612,7 @@ public: } } - // pool user_context (75) + // pool user_context ElementPtr user_context = out_bindings[75]->getJSON(); if (user_context) { last_pool->setContext(user_context); @@ -645,7 +634,7 @@ public: (out_bindings[20]->getInteger() > last_pd_pool_id)) { last_pd_pool_id = out_bindings[20]->getInteger(); - // excluded_prefix (76) and excluded_prefix_length (77) + // excluded_prefix and excluded_prefix_length IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS(); if (!out_bindings[76]->amNull()) { excluded_prefix = IOAddress(out_bindings[76]->getString()); @@ -655,12 +644,12 @@ public: out_bindings[23]->getInteger(), excluded_prefix, out_bindings[77]->getInteger()); - // pd pool client_class (78) + // pd pool client_class if (!out_bindings[78]->amNull()) { last_pd_pool->allowClientClass(out_bindings[78]->getString()); } - // pd pool require_client_classes (79) + // pd pool require_client_classes ElementPtr require_element = out_bindings[79]->getJSON(); if (require_element) { if (require_element->getType() != Element::list) { @@ -677,7 +666,7 @@ public: } } - // pd pool user_context (80) + // pd pool user_context ElementPtr user_context = out_bindings[80]->getJSON(); if (user_context) { last_pd_pool->setContext(user_context); @@ -904,12 +893,12 @@ public: last_pool = Pool6::create(Lease::TYPE_NA, IOAddress(out_bindings[1]->getString()), IOAddress(out_bindings[2]->getString())); - // pool client_class (4) + // pool client_class if (!out_bindings[4]->amNull()) { last_pool->allowClientClass(out_bindings[4]->getString()); } - // pool require_client_classes (5) + // pool require_client_classes ElementPtr require_element = out_bindings[5]->getJSON(); if (require_element) { if (require_element->getType() != Element::list) { @@ -926,19 +915,17 @@ public: } } - // pool user_context (6) + // pool user_context ElementPtr user_context = out_bindings[6]->getJSON(); if (user_context) { last_pool->setContext(user_context); } - // pool: modification_ts (7) - pools.push_back(last_pool); pool_ids.push_back(last_pool_id); } - // Parse pool specific option (8). + // Parse pool specific option between 8 and 20 if (last_pool && !out_bindings[8]->amNull() && (last_pool_option_id < out_bindings[8]->getInteger())) { last_pool_option_id = out_bindings[8]->getInteger(); @@ -1007,7 +994,7 @@ public: last_pd_pool_id = out_bindings[0]->getInteger(); - // excluded_prefix (5) and excluded_prefix_length (6) + // excluded_prefix and excluded_prefix_length IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS(); if (!out_bindings[5]->amNull()) { excluded_prefix = IOAddress(out_bindings[5]->getString()); @@ -1019,12 +1006,12 @@ public: excluded_prefix, out_bindings[6]->getInteger()); - // pd pool client_class (7) + // pd pool client_class if (!out_bindings[7]->amNull()) { last_pd_pool->allowClientClass(out_bindings[7]->getString()); } - // pd pool require_client_classes (8) + // pd pool require_client_classes ElementPtr require_element = out_bindings[8]->getJSON(); if (require_element) { if (require_element->getType() != Element::list) { @@ -1041,19 +1028,17 @@ public: } } - // pd pool user_context (9) + // pd pool user_context ElementPtr user_context = out_bindings[9]->getJSON(); if (user_context) { last_pd_pool->setContext(user_context); } - // pd pool modification_ts (10) - pd_pools.push_back(last_pd_pool); 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 23 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(); @@ -1178,16 +1163,6 @@ public: required_classes_element->add(Element::create(*required_class)); } - // Create binding for host reservation mode. - MySqlBindingPtr hr_mode_binding; - auto hr_mode = subnet->getHostReservationMode(Network::Inheritance::NONE); - if (!hr_mode.unspecified()) { - hr_mode_binding = MySqlBinding::createInteger(static_cast - (hr_mode.get())); - } else { - hr_mode_binding = MySqlBinding::createNull(); - } - // Create binding for DDNS replace client name mode. MySqlBindingPtr ddns_rcn_mode_binding; auto ddns_rcn_mode = subnet->getDdnsReplaceClientNameMode(Network::Inheritance::NONE); @@ -1251,7 +1226,7 @@ public: createInputRelayBinding(subnet), createBinding(subnet->getT1(Network::Inheritance::NONE)), createInputRequiredClassesBinding(subnet), - hr_mode_binding, + MySqlBinding::condCreateBool(subnet->getReservationsGlobal(Network::Inheritance::NONE)), shared_network_binding, createInputContextBinding(subnet), createBinding(subnet->getValid(Network::Inheritance::NONE)), @@ -1266,7 +1241,9 @@ public: MySqlBinding::condCreateBool(subnet->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)), ddns_rcn_mode_binding, MySqlBinding::condCreateString(subnet->getDdnsGeneratedPrefix(Network::Inheritance::NONE)), - MySqlBinding::condCreateString(subnet->getDdnsQualifyingSuffix(Network::Inheritance::NONE)) + MySqlBinding::condCreateString(subnet->getDdnsQualifyingSuffix(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getReservationsInSubnet(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(subnet->getReservationsOutOfPool(Network::Inheritance::NONE)) }; MySqlTransaction transaction(conn_); @@ -1556,7 +1533,7 @@ public: MySqlBinding::createString(RELAY_BUF_LENGTH), // relay MySqlBinding::createInteger(), // renew_timer MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // require_client_classes - MySqlBinding::createInteger(), // reservation_mode + MySqlBinding::createInteger(), // reservations_global MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context MySqlBinding::createInteger(), // valid_lifetime MySqlBinding::createInteger(), // option: option_id @@ -1586,6 +1563,8 @@ public: MySqlBinding::createInteger(), // ddns_replace_client_name MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_generated_prefix MySqlBinding::createString(DNS_NAME_BUF_LENGTH), // ddns_qualifying_suffix + MySqlBinding::createInteger(), // reservations_in_subnet + MySqlBinding::createInteger(), // reservations_out_of_pool MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag }; @@ -1684,10 +1663,9 @@ public: } } - // reservation_mode + // reservations_global if (!out_bindings[11]->amNull()) { - last_network->setHostReservationMode(static_cast - (out_bindings[11]->getIntegerOrDefault(Network::HR_ALL))); + last_network->setReservationsGlobal(out_bindings[11]->getBool()); } // user_context @@ -1732,38 +1710,46 @@ public: // {min,max)_valid_lifetime - // ddns_send_updates at 35 + // ddns_send_updates if (!out_bindings[35]->amNull()) { last_network->setDdnsSendUpdates(out_bindings[35]->getBool()); } - // ddns_override_no_update at 36 + // ddns_override_no_update if (!out_bindings[36]->amNull()) { last_network->setDdnsOverrideNoUpdate(out_bindings[36]->getBool()); } - // ddns_override_client_update at 37 + // ddns_override_client_update if (!out_bindings[37]->amNull()) { last_network->setDdnsOverrideClientUpdate(out_bindings[37]->getBool()); } - // ddns_replace_client_name at 38 + // ddns_replace_client_name if (!out_bindings[38]->amNull()) { last_network->setDdnsReplaceClientNameMode(static_cast (out_bindings[38]->getInteger())); } - // ddns_generated_prefix at 39 + // ddns_generated_prefix if (!out_bindings[39]->amNull()) { last_network->setDdnsGeneratedPrefix(out_bindings[39]->getString()); } - // ddns_qualifying_suffix at 40 + // ddns_qualifying_suffix if (!out_bindings[40]->amNull()) { last_network->setDdnsQualifyingSuffix(out_bindings[40]->getString()); } - // server_tag at 41 + // reservations_in_subnet + if (!out_bindings[41]->amNull()) { + last_network->setReservationsInSubnet(out_bindings[41]->getBool()); + } + + // reservations_out_of_pool + if (!out_bindings[42]->amNull()) { + last_network->setReservationsOutOfPool(out_bindings[42]->getBool()); + } // Add the shared network. auto ret = shared_networks.push_back(last_network); @@ -1788,9 +1774,9 @@ public: } // Check for new server tags. - if (!out_bindings[41]->amNull() && - (last_tag != out_bindings[41]->getString())) { - last_tag = out_bindings[41]->getString(); + if (!out_bindings[43]->amNull() && + (last_tag != out_bindings[43]->getString())) { + last_tag = out_bindings[43]->getString(); if (!last_tag.empty() && !last_network->hasServerTag(ServerTag(last_tag))) { last_network->setServerTag(last_tag); } @@ -1895,16 +1881,6 @@ public: " (unassigned) is unsupported at the moment"); } - // Create binding for host reservation mode. - MySqlBindingPtr hr_mode_binding; - auto hr_mode = shared_network->getHostReservationMode(Network::Inheritance::NONE); - if (!hr_mode.unspecified()) { - hr_mode_binding = MySqlBinding::createInteger(static_cast - (hr_mode.get())); - } else { - hr_mode_binding = MySqlBinding::createNull(); - } - // Create the binding holding interface_id. MySqlBindingPtr interface_id_binding = MySqlBinding::createNull(); auto opt_iface_id = shared_network->getInterfaceId(); @@ -1939,7 +1915,7 @@ public: createInputRelayBinding(shared_network), createBinding(shared_network->getT1(Network::Inheritance::NONE)), createInputRequiredClassesBinding(shared_network), - hr_mode_binding, + MySqlBinding::condCreateBool(shared_network->getReservationsGlobal(Network::Inheritance::NONE)), createInputContextBinding(shared_network), createBinding(shared_network->getValid(Network::Inheritance::NONE)), createMinBinding(shared_network->getValid(Network::Inheritance::NONE)), @@ -1953,7 +1929,9 @@ public: MySqlBinding::condCreateBool(shared_network->getDdnsOverrideClientUpdate(Network::Inheritance::NONE)), ddns_rcn_mode_binding, MySqlBinding::condCreateString(shared_network->getDdnsGeneratedPrefix(Network::Inheritance::NONE)), - MySqlBinding::condCreateString(shared_network->getDdnsQualifyingSuffix(Network::Inheritance::NONE)) + MySqlBinding::condCreateString(shared_network->getDdnsQualifyingSuffix(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getReservationsInSubnet(Network::Inheritance::NONE)), + MySqlBinding::condCreateBool(shared_network->getReservationsOutOfPool(Network::Inheritance::NONE)) }; MySqlTransaction transaction(conn_); @@ -2911,7 +2889,7 @@ TaggedStatementArray tagged_statements = { { " relay," " renew_timer," " require_client_classes," - " reservation_mode," + " reservations_global," " shared_network_name," " user_context," " valid_lifetime," @@ -2926,9 +2904,11 @@ TaggedStatementArray tagged_statements = { { " ddns_override_client_update," " ddns_replace_client_name," " ddns_generated_prefix," - " ddns_qualifying_suffix" + " ddns_qualifying_suffix," + " reservations_in_subnet," + " reservations_out_of_pool" ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," - " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, + " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, // Insert association of the subnet with a server. { MySqlConfigBackendDHCPv6Impl::INSERT_SUBNET6_SERVER, @@ -2960,7 +2940,7 @@ TaggedStatementArray tagged_statements = { { " relay," " renew_timer," " require_client_classes," - " reservation_mode," + " reservations_global," " user_context," " valid_lifetime," " min_valid_lifetime," @@ -2974,9 +2954,11 @@ TaggedStatementArray tagged_statements = { { " ddns_override_client_update," " ddns_replace_client_name," " ddns_generated_prefix," - " ddns_qualifying_suffix" + " ddns_qualifying_suffix," + " reservations_in_subnet," + " reservations_out_of_pool" ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," - " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, + " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" }, // Insert association of the shared network with a server. { MySqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6_SERVER, @@ -3029,7 +3011,7 @@ TaggedStatementArray tagged_statements = { { " relay = ?," " renew_timer = ?," " require_client_classes = ?," - " reservation_mode = ?," + " reservations_global = ?," " shared_network_name = ?," " user_context = ?," " valid_lifetime = ?," @@ -3044,7 +3026,9 @@ TaggedStatementArray tagged_statements = { { " ddns_override_client_update = ?," " ddns_replace_client_name = ?," " ddns_generated_prefix = ?," - " ddns_qualifying_suffix = ? " + " ddns_qualifying_suffix = ?," + " reservations_in_subnet = ?," + " reservations_out_of_pool = ? " "WHERE subnet_id = ? OR subnet_prefix = ?" }, // Update existing shared network. @@ -3062,7 +3046,7 @@ TaggedStatementArray tagged_statements = { { " relay = ?," " renew_timer = ?," " require_client_classes = ?," - " reservation_mode = ?," + " reservations_global = ?," " user_context = ?," " valid_lifetime = ?," " min_valid_lifetime = ?," @@ -3076,7 +3060,9 @@ TaggedStatementArray tagged_statements = { { " ddns_override_client_update = ?," " ddns_replace_client_name = ?," " ddns_generated_prefix = ?," - " ddns_qualifying_suffix = ? " + " ddns_qualifying_suffix = ?," + " reservations_in_subnet = ?," + " reservations_out_of_pool = ? " "WHERE name = ?" }, // Update existing option definition. 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 21d1b7676a..01d7ca1708 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h +++ b/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h @@ -66,7 +66,7 @@ namespace { " s.relay," \ " s.renew_timer," \ " s.require_client_classes," \ - " s.reservation_mode," \ + " s.reservations_global," \ " s.server_hostname," \ " s.shared_network_name," \ " s.user_context," \ @@ -115,6 +115,8 @@ namespace { " s.ddns_replace_client_name," \ " s.ddns_generated_prefix," \ " s.ddns_qualifying_suffix," \ + " s.reservations_in_subnet," \ + " s.reservations_out_of_pool," \ " srv.tag " \ "FROM dhcp4_subnet AS s " \ server_join \ @@ -164,7 +166,7 @@ namespace { " s.relay," \ " s.renew_timer," \ " s.require_client_classes," \ - " s.reservation_mode," \ + " s.reservations_global," \ " s.shared_network_name," \ " s.user_context," \ " s.valid_lifetime," \ @@ -240,6 +242,8 @@ namespace { " s.ddns_replace_client_name," \ " s.ddns_generated_prefix," \ " s.ddns_qualifying_suffix," \ + " s.reservations_in_subnet," \ + " s.reservations_out_of_pool," \ " srv.tag " \ "FROM dhcp6_subnet AS s " \ server_join \ @@ -415,7 +419,7 @@ namespace { " n.relay," \ " n.renew_timer," \ " n.require_client_classes," \ - " n.reservation_mode," \ + " n.reservations_global," \ " n.user_context," \ " n.valid_lifetime," \ " o.option_id," \ @@ -445,6 +449,8 @@ namespace { " n.ddns_replace_client_name," \ " n.ddns_generated_prefix," \ " n.ddns_qualifying_suffix," \ + " n.reservations_in_subnet," \ + " n.reservations_out_of_pool," \ " s.tag " \ "FROM dhcp4_shared_network AS n " \ server_join \ @@ -492,7 +498,7 @@ namespace { " n.relay," \ " n.renew_timer," \ " n.require_client_classes," \ - " n.reservation_mode," \ + " n.reservations_global," \ " n.user_context," \ " n.valid_lifetime," \ " o.option_id," \ @@ -522,6 +528,8 @@ namespace { " n.ddns_replace_client_name," \ " n.ddns_generated_prefix," \ " n.ddns_qualifying_suffix," \ + " n.reservations_in_subnet," \ + " n.reservations_out_of_pool," \ " s.tag " \ "FROM dhcp6_shared_network AS n " \ server_join \ diff --git a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc index 56958c7d2c..4a2feb7cbf 100644 --- a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc @@ -161,7 +161,9 @@ public: subnet->setT1(1234); subnet->requireClientClass("required-class1"); subnet->requireClientClass("required-class2"); - subnet->setHostReservationMode(Subnet4::HR_DISABLED); + subnet->setReservationsGlobal(false); + subnet->setReservationsInSubnet(false); + subnet->setReservationsOutOfPool(false); subnet->setSname("server-hostname"); subnet->setContext(user_context); subnet->setValid(555555); @@ -260,7 +262,9 @@ public: shared_network->setT1(1234); shared_network->requireClientClass("required-class1"); shared_network->requireClientClass("required-class2"); - shared_network->setHostReservationMode(Subnet4::HR_DISABLED); + shared_network->setReservationsGlobal(false); + shared_network->setReservationsInSubnet(false); + shared_network->setReservationsOutOfPool(false); shared_network->setContext(user_context); shared_network->setValid(5555); shared_network->setCalculateTeeTimes(true); @@ -1319,8 +1323,14 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4WithOptionalUnspecified) { EXPECT_TRUE(returned_subnet->getT2().unspecified()); EXPECT_EQ(0, returned_subnet->getT2().get()); - EXPECT_TRUE(returned_subnet->getHostReservationMode().unspecified()); - EXPECT_EQ(Network::HR_ALL, returned_subnet->getHostReservationMode().get()); + EXPECT_TRUE(returned_subnet->getReservationsGlobal().unspecified()); + EXPECT_FALSE(returned_subnet->getReservationsGlobal().get()); + + EXPECT_TRUE(returned_subnet->getReservationsInSubnet().unspecified()); + EXPECT_TRUE(returned_subnet->getReservationsInSubnet().get()); + + EXPECT_TRUE(returned_subnet->getReservationsOutOfPool().unspecified()); + EXPECT_FALSE(returned_subnet->getReservationsOutOfPool().get()); EXPECT_TRUE(returned_subnet->getCalculateTeeTimes().unspecified()); EXPECT_FALSE(returned_subnet->getCalculateTeeTimes().get()); @@ -2338,8 +2348,14 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetwork4WithOptionalUnspecified) { EXPECT_TRUE(returned_network->getT2().unspecified()); EXPECT_EQ(0, returned_network->getT2().get()); - EXPECT_TRUE(returned_network->getHostReservationMode().unspecified()); - EXPECT_EQ(Network::HR_ALL, returned_network->getHostReservationMode().get()); + EXPECT_TRUE(returned_network->getReservationsGlobal().unspecified()); + EXPECT_FALSE(returned_network->getReservationsGlobal().get()); + + EXPECT_TRUE(returned_network->getReservationsInSubnet().unspecified()); + EXPECT_TRUE(returned_network->getReservationsInSubnet().get()); + + EXPECT_TRUE(returned_network->getReservationsOutOfPool().unspecified()); + EXPECT_FALSE(returned_network->getReservationsOutOfPool().get()); EXPECT_TRUE(returned_network->getCalculateTeeTimes().unspecified()); EXPECT_FALSE(returned_network->getCalculateTeeTimes().get()); diff --git a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc index 7fbfd63973..ebea6fc6ca 100644 --- a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc @@ -157,7 +157,9 @@ public: subnet->setT1(1234); subnet->requireClientClass("required-class1"); subnet->requireClientClass("required-class2"); - subnet->setHostReservationMode(Subnet4::HR_DISABLED); + subnet->setReservationsGlobal(false); + subnet->setReservationsInSubnet(false); + subnet->setReservationsOutOfPool(false); subnet->setContext(user_context); subnet->setValid(555555); subnet->setPreferred(4444444); @@ -307,7 +309,9 @@ public: shared_network->setT1(1234); shared_network->requireClientClass("required-class1"); shared_network->requireClientClass("required-class2"); - shared_network->setHostReservationMode(Subnet6::HR_DISABLED); + shared_network->setReservationsGlobal(false); + shared_network->setReservationsInSubnet(false); + subnet->setReservationsOutOfPool(false); shared_network->setContext(user_context); shared_network->setValid(5555); shared_network->setPreferred(4444); @@ -1367,8 +1371,14 @@ TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6WithOptionalUnspecified) { EXPECT_TRUE(returned_subnet->getT2().unspecified()); EXPECT_EQ(0, returned_subnet->getT2().get()); - EXPECT_TRUE(returned_subnet->getHostReservationMode().unspecified()); - EXPECT_EQ(Network::HR_ALL, returned_subnet->getHostReservationMode().get()); + EXPECT_TRUE(returned_subnet->getReservationsGlobal().unspecified()); + EXPECT_FALSE(returned_subnet->getReservationsGlobal().get()); + + EXPECT_TRUE(returned_subnet->getReservationsInSubnet().unspecified()); + EXPECT_TRUE(returned_subnet->getReservationsInSubnet().get()); + + EXPECT_TRUE(returned_subnet->getReservationsOutOfPool().unspecified()); + EXPECT_FALSE(returned_subnet->getReservationsOutOfPool().get()); EXPECT_TRUE(returned_subnet->getCalculateTeeTimes().unspecified()); EXPECT_FALSE(returned_subnet->getCalculateTeeTimes().get()); @@ -2376,8 +2386,14 @@ TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6WithOptionalUnspecified) { EXPECT_TRUE(returned_network->getT2().unspecified()); EXPECT_EQ(0, returned_network->getT2().get()); - EXPECT_TRUE(returned_network->getHostReservationMode().unspecified()); - EXPECT_EQ(Network::HR_ALL, returned_network->getHostReservationMode().get()); + EXPECT_TRUE(returned_network->getReservationsGlobal().unspecified()); + EXPECT_FALSE(returned_network->getReservationsGlobal().get()); + + EXPECT_TRUE(returned_network->getReservationsInSubnet().unspecified()); + EXPECT_TRUE(returned_network->getReservationsInSubnet().get()); + + EXPECT_TRUE(returned_network->getReservationsOutOfPool().unspecified()); + EXPECT_FALSE(returned_network->getReservationsOutOfPool().get()); EXPECT_TRUE(returned_network->getCalculateTeeTimes().unspecified()); EXPECT_FALSE(returned_network->getCalculateTeeTimes().get()); diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index 922f4c5d96..9105d37e6a 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -535,7 +535,7 @@ isAllocated(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const { ConstHostPtr AllocEngine::ClientContext6::currentHost() const { Subnet6Ptr subnet = host_subnet_ ? host_subnet_ : subnet_; - if (subnet && (subnet_->getHostReservationMode() & Network::HR_IN_SUBNET_FLAG)) { + if (subnet && subnet->getReservationsInSubnet()) { auto host = hosts_.find(subnet->getID()); if (host != hosts_.cend()) { return (host->second); @@ -548,7 +548,7 @@ AllocEngine::ClientContext6::currentHost() const { ConstHostPtr AllocEngine::ClientContext6::globalHost() const { Subnet6Ptr subnet = host_subnet_ ? host_subnet_ : subnet_; - if (subnet && (subnet_->getHostReservationMode() & Network::HR_GLOBAL_FLAG)) { + if (subnet && subnet_->getReservationsGlobal()) { auto host = hosts_.find(SUBNET_ID_GLOBAL); if (host != hosts_.cend()) { return (host->second); @@ -597,14 +597,14 @@ AllocEngine::findReservation(ClientContext6& ctx) { SharedNetwork6Ptr network; subnet->getSharedNetwork(network); - if (subnet->getHostReservationMode() & Network::HR_GLOBAL_FLAG) { + if (subnet->getReservationsGlobal()) { ConstHostPtr ghost = findGlobalReservation(ctx); if (ghost) { ctx.hosts_[SUBNET_ID_GLOBAL] = ghost; - // @todo In theory, to support global as part of HR_ALL, - // we would just keep going, instead of returning. - if (subnet->getHostReservationMode() == Network::HR_GLOBAL) { + // If we had only to fetch global reservations it is done. + if (!subnet->getReservationsInSubnet() && + !subnet->getReservationsOutOfPool()) { return; } } @@ -641,9 +641,9 @@ AllocEngine::findReservation(ClientContext6& ctx) { while (subnet) { // Only makes sense to get reservations if the client has access - // to the class and host reservations are enabled. + // to the class and host reservations are enabled for this subnet. if (subnet->clientSupported(ctx.query_->getClasses()) && - (subnet->getHostReservationMode() != Network::HR_DISABLED)) { + (subnet->getReservationsInSubnet() || subnet->getReservationsOutOfPool())) { // Iterate over configured identifiers in the order of preference // and try to use each of them to search for the reservations. for (auto id_pair : ctx.host_identifiers_) { @@ -916,9 +916,6 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { continue; } - // Check which host reservation mode is supported in this subnet. - Network::HRMode hr_mode = subnet->getHostReservationMode(); - /// @todo: We support only one hint for now Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, hint); @@ -929,9 +926,9 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // it has been reserved for us we would have already allocated a lease. ConstHostCollection hosts; - bool in_subnet = (hr_mode & Network::HR_IN_SUBNET_FLAG); - bool out_of_pool = (hr_mode & Network::HR_OUT_OF_POOL_FLAG); - // The HR_OUT_OF_POOL_FLAG indicates that no client should be assigned reservations + bool in_subnet = subnet->getReservationsInSubnet(); + bool out_of_pool = subnet->getReservationsOutOfPool(); + // The out-of-pool flag indicates that no client should be assigned reservations // from within the dynamic pool, and for that reason we only look at reservations that // are outside the pools, hence the inPool check. if ((in_subnet && !out_of_pool) || @@ -969,9 +966,9 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // If the lease is expired, we may likely reuse it, but... ConstHostCollection hosts; - bool in_subnet = (hr_mode & Network::HR_IN_SUBNET_FLAG); - bool out_of_pool = (hr_mode & Network::HR_OUT_OF_POOL_FLAG); - // The HR_OUT_OF_POOL_FLAG indicates that no client should be assigned reservations + bool in_subnet = subnet->getReservationsInSubnet(); + bool out_of_pool = subnet->getReservationsOutOfPool(); + // The out-of-pool flag indicates that no client should be assigned reservations // from within the dynamic pool, and for that reason we only look at reservations that // are outside the pools, hence the inPool check. if ((in_subnet && !out_of_pool) || @@ -1053,7 +1050,8 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { continue; } uint64_t max_attempts = (attempts_ > 0 ? attempts_ : possible_attempts); - Network::HRMode hr_mode = subnet->getHostReservationMode(); + bool in_subnet = subnet->getReservationsInSubnet(); + bool out_of_pool = subnet->getReservationsOutOfPool(); // Set the default status code in case the lease6_select callouts // do not exist and the callout handle has a status returned by @@ -1084,8 +1082,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { } // First check for reservation when it is the choice. - if (check_reservation_first && ((hr_mode & Network::HR_IN_SUBNET_FLAG) && - !(hr_mode & Network::HR_OUT_OF_POOL_FLAG))) { + if (check_reservation_first && in_subnet && !out_of_pool) { auto hosts = getIPv6Resrv(subnet->getID(), candidate); if (!hosts.empty()) { // Don't allocate. @@ -1110,8 +1107,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { /// In-pool reservations: Check if this address is reserved for someone /// else. There is no need to check for whom it is reserved, because if /// it has been reserved for us we would have already allocated a lease. - if (!check_reservation_first && (hr_mode & Network::HR_IN_SUBNET_FLAG) && - !(hr_mode & Network::HR_OUT_OF_POOL_FLAG)) { + if (!check_reservation_first && in_subnet && !out_of_pool) { auto hosts = getIPv6Resrv(subnet->getID(), candidate); if (!hosts.empty()) { // Don't allocate. @@ -1143,8 +1139,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // allocation attempts. } else if (existing->expired()) { // Make sure it's not reserved. - if (!check_reservation_first && (hr_mode & Network::HR_IN_SUBNET_FLAG) && - !(hr_mode & Network::HR_OUT_OF_POOL_FLAG)) { + if (!check_reservation_first && in_subnet && !out_of_pool) { auto hosts = getIPv6Resrv(subnet->getID(), candidate); if (!hosts.empty()) { // Don't allocate. @@ -1265,11 +1260,8 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, ConstHostPtr host = ctx.hosts_[subnet_id]; - // Check which host reservation mode is supported in this subnet. - Network::HRMode hr_mode = subnet->getHostReservationMode(); - - bool in_subnet = (hr_mode & Network::HR_IN_SUBNET_FLAG); - bool out_of_pool = (hr_mode & Network::HR_OUT_OF_POOL_FLAG); + bool in_subnet = subnet->getReservationsInSubnet(); + bool out_of_pool = subnet->getReservationsOutOfPool(); // Get the IPv6 reservations of specified type. const IPv6ResrvRange& reservs = host->getIPv6Reservations(type); @@ -1284,7 +1276,7 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, continue; } - // The HR_OUT_OF_POOL_FLAG indicates that no client should be assigned reservations + // The out-of-pool flag indicates that no client should be assigned reservations // from within the dynamic pool, and for that reason we only look at reservations that // are outside the pools, hence the inPool check. if ((in_subnet && !out_of_pool) || @@ -1490,7 +1482,9 @@ AllocEngine::removeNonmatchingReservedLeases6(ClientContext6& ctx, } // If host reservation is disabled (so there are no reserved leases) // use the simplified version. - if (ctx.subnet_->getHostReservationMode() == Network::HR_DISABLED) { + if (!ctx.subnet_->getReservationsGlobal() && + !ctx.subnet_->getReservationsInSubnet() && + !ctx.subnet_->getReservationsOutOfPool()) { removeNonmatchingReservedNoHostLeases6(ctx, existing_leases); return; } @@ -2978,11 +2972,9 @@ addressReserved(const IOAddress& address, const AllocEngine::ClientContext4& ctx if (!ctx.subnet_) { return false; } - // Check which host reservation mode is supported in this subnet. - Network::HRMode hr_mode = ctx.subnet_->getHostReservationMode(); - bool in_subnet = (hr_mode & Network::HR_IN_SUBNET_FLAG); - bool out_of_pool = (hr_mode & Network::HR_OUT_OF_POOL_FLAG); - // The HR_OUT_OF_POOL_FLAG indicates that no client should be assigned reservations + bool in_subnet = ctx.subnet_->getReservationsInSubnet(); + bool out_of_pool = ctx.subnet_->getReservationsOutOfPool(); + // The out-of-pool flag indicates that no client should be assigned reservations // from within the dynamic pool, and for that reason we only look at reservations that // are outside the pools, hence the inPool check. if ((in_subnet && !out_of_pool) || @@ -3048,13 +3040,14 @@ hasAddressReservation(AllocEngine::ClientContext4& ctx) { Subnet4Ptr subnet = ctx.subnet_; while (subnet) { - if (subnet->getHostReservationMode() & Network::HR_GLOBAL_FLAG) { + if (subnet->getReservationsGlobal()) { auto host = ctx.hosts_.find(SUBNET_ID_GLOBAL); bool found = (host != ctx.hosts_.end() && !(host->second->getIPv4Reservation().isV4Zero())); // if we want global + other modes we would need to // return only if true, else continue - if (subnet->getHostReservationMode() == Network::HR_GLOBAL) { + if (!subnet->getReservationsInSubnet() && + !subnet->getReservationsOutOfPool()) { return (found); } else { if (found) { @@ -3064,11 +3057,9 @@ hasAddressReservation(AllocEngine::ClientContext4& ctx) { } auto host = ctx.hosts_.find(subnet->getID()); - // Check which host reservation mode is supported in this subnet. - Network::HRMode hr_mode = subnet->getHostReservationMode(); - bool in_subnet = (hr_mode & Network::HR_IN_SUBNET_FLAG); - bool out_of_pool = (hr_mode & Network::HR_OUT_OF_POOL_FLAG); - // The HR_OUT_OF_POOL_FLAG indicates that no client should be assigned reservations + bool in_subnet = subnet->getReservationsInSubnet(); + bool out_of_pool = subnet->getReservationsOutOfPool(); + // The out-of-pool flag indicates that no client should be assigned reservations // from within the dynamic pool, and for that reason we only look at reservations that // are outside the pools, hence the inPool check. if (host != ctx.hosts_.end()) { @@ -3252,7 +3243,7 @@ AllocEngine::ClientContext4::ClientContext4(const Subnet4Ptr& subnet, ConstHostPtr AllocEngine::ClientContext4::currentHost() const { - if (subnet_ && (subnet_->getHostReservationMode() & Network::HR_IN_SUBNET_FLAG)) { + if (subnet_ && subnet_->getReservationsInSubnet()) { auto host = hosts_.find(subnet_->getID()); if (host != hosts_.cend()) { return (host->second); @@ -3264,7 +3255,7 @@ AllocEngine::ClientContext4::currentHost() const { ConstHostPtr AllocEngine::ClientContext4::globalHost() const { - if (subnet_ && (subnet_->getHostReservationMode() & Network::HR_GLOBAL_FLAG)) { + if (subnet_ && subnet_->getReservationsGlobal()) { auto host = hosts_.find(SUBNET_ID_GLOBAL); if (host != hosts_.cend()) { return (host->second); @@ -3351,14 +3342,14 @@ AllocEngine::findReservation(ClientContext4& ctx) { SharedNetwork4Ptr network; subnet->getSharedNetwork(network); - if (subnet->getHostReservationMode() & Network::HR_GLOBAL_FLAG) { + if (subnet->getReservationsGlobal()) { ConstHostPtr ghost = findGlobalReservation(ctx); if (ghost) { ctx.hosts_[SUBNET_ID_GLOBAL] = ghost; - // @todo In theory, to support global as part of HR_ALL, - // we would just keep going, instead of returning. - if (subnet->getHostReservationMode() == Network::HR_GLOBAL) { + // If we had only to fetch global reservations it is done. + if (!subnet->getReservationsInSubnet() && + !subnet->getReservationsOutOfPool()) { return; } } @@ -3399,7 +3390,7 @@ AllocEngine::findReservation(ClientContext4& ctx) { // Only makes sense to get reservations if the client has access // to the class. if (subnet->clientSupported(ctx.query_->getClasses()) && - (subnet->getHostReservationMode() != Network::HR_DISABLED)) { + (subnet->getReservationsInSubnet() || subnet->getReservationsOutOfPool())) { // Iterate over configured identifiers in the order of preference // and try to use each of them to search for the reservations. BOOST_FOREACH(const IdentifierPair& id_pair, ctx.host_identifiers_) { diff --git a/src/lib/dhcpsrv/parsers/base_network_parser.cc b/src/lib/dhcpsrv/parsers/base_network_parser.cc index 6dcd822d85..baad63e898 100644 --- a/src/lib/dhcpsrv/parsers/base_network_parser.cc +++ b/src/lib/dhcpsrv/parsers/base_network_parser.cc @@ -7,7 +7,6 @@ #include #include #include -#include #include #include @@ -17,6 +16,44 @@ using namespace isc::util; namespace isc { namespace dhcp { +bool +BaseNetworkParser::moveReservationMode(ElementPtr config) { + if (!config->contains("reservation-mode")) { + return (false); + } + if (config->contains("reservations-global") || + config->contains("reservations-in-subnet") || + config->contains("reservations-out-of-pool")) { + isc_throw(DhcpConfigError, "invalid use of both 'reservation-mode'" + " one of 'reservations-global', 'reservations-in-subnet'" + " or 'reservations-out-of-pool' parameters"); + } + std::string hr_mode = getString(config, "reservation-mode"); + if ((hr_mode == "disabled") || (hr_mode == "off")) { + config->set("reservations-global", Element::create(false)); + config->set("reservations-in-subnet", Element::create(false)); + config->set("reservations-out-of-pool", Element::create(false)); + } else if (hr_mode == "out-of-pool") { + config->set("reservations-global", Element::create(false)); + config->set("reservations-in-subnet", Element::create(true)); + config->set("reservations-out-of-pool", Element::create(true)); + } else if (hr_mode == "global") { + config->set("reservations-global", Element::create(true)); + config->set("reservations-in-subnet", Element::create(false)); + config->set("reservations-out-of-pool", Element::create(false)); + } else if (hr_mode == "all") { + config->set("reservations-global", Element::create(false)); + config->set("reservations-in-subnet", Element::create(true)); + config->set("reservations-out-of-pool", Element::create(false)); + } else { + isc_throw(DhcpConfigError, "invalid reservation-mode parameter: '" + << hr_mode << "' (" + << getPosition("reservation-mode", config) << ")"); + } + config->remove("reservation-mode"); + return (true); +} + const Triplet BaseNetworkParser::parseLifetime(const ConstElementPtr& scope, const std::string& name) { @@ -136,6 +173,21 @@ BaseNetworkParser::parseCommon(const ConstElementPtr& network_data, network->setStoreExtendedInfo(getBoolean(network_data, "store-extended-info")); } + + if (network_data->contains("reservations-global")) { + network->setReservationsGlobal(getBoolean(network_data, + "reservations-global")); + } + + if (network_data->contains("reservations-in-subnet")) { + network->setReservationsInSubnet(getBoolean(network_data, + "reservations-in-subnet")); + } + + if (network_data->contains("reservations-out-of-pool")) { + network->setReservationsOutOfPool(getBoolean(network_data, + "reservations-out-of-pool")); + } } void @@ -198,61 +250,6 @@ BaseNetworkParser::parseCacheParams(const ConstElementPtr& network_data, } } -void -BaseNetworkParser::parseHostReservationMode(const data::ConstElementPtr& network_data, - NetworkPtr& network) { - if (network_data->contains("reservation-mode")) { - bool found = false; - if (network_data->contains("reservations-out-of-pool") || - network_data->contains("reservations-in-subnet") || - network_data->contains("reservations-global")) { - found = true; - } - if (found) { - isc_throw(DhcpConfigError, "invalid use of both 'reservation-mode'" - " and one of 'reservations-out-of-pool'" - " , 'reservations-in-subnet' or" - " 'reservations-global' parameters"); - } - try { - std::string hr_mode = getString(network_data, "reservation-mode"); - network->setHostReservationMode(Network::hrModeFromString(hr_mode)); - } catch (const BadValue& ex) { - isc_throw(DhcpConfigError, "invalid reservation-mode parameter: " - << ex.what() << " (" << getPosition("reservation-mode", - network_data) << ")"); - } - } -} - -void -BaseNetworkParser::parseHostReservationModes(const data::ConstElementPtr& network_data, - NetworkPtr& network) { - bool found = false; - if (network_data->contains("reservations-out-of-pool") || - network_data->contains("reservations-in-subnet") || - network_data->contains("reservations-global")) { - found = true; - } - if (found) { - if (network_data->contains("reservation-mode")) { - isc_throw(DhcpConfigError, "invalid use of both 'reservation-mode'" - " and one of 'reservations-out-of-pool'" - " , 'reservations-in-subnet' or" - " 'reservations-global' parameters"); - } - } else { - return; - } - try { - HostReservationModesParser parser; - Network::HRMode flags = parser.parse(network_data); - network->setHostReservationMode(flags); - } catch (const BadValue& ex) { - isc_throw(DhcpConfigError, "invalid parameter: " << ex.what()); - } -} - void BaseNetworkParser::parseDdnsParams(const data::ConstElementPtr& network_data, NetworkPtr& network) { diff --git a/src/lib/dhcpsrv/parsers/base_network_parser.h b/src/lib/dhcpsrv/parsers/base_network_parser.h index 992736a84a..2d5b4e44d3 100644 --- a/src/lib/dhcpsrv/parsers/base_network_parser.h +++ b/src/lib/dhcpsrv/parsers/base_network_parser.h @@ -17,6 +17,19 @@ namespace dhcp { /// @brief Common configuration parser for shared networks /// and subnets. class BaseNetworkParser : public data::SimpleParser { +public: + + /// @brief Moves deprecated reservation-mode parameter to + /// new reservations flags. + /// + /// @param config [in/out] configuration to alter. + /// @throw DhcpConfigError on error e.g. when both reservation-mode + /// and a flag are specified. + /// @return true if reservation-mode parameter has been replaces with + /// new reservations-global, reservations-in-subnet and + /// reservations-out-of-pool parameters, false otherwise. + static bool moveReservationMode(isc::data::ElementPtr config); + protected: /// @brief Parses DHCP lifetime. @@ -37,6 +50,9 @@ protected: /// - rebind-timer, /// - valid-lifetime, /// - store-extended-info + /// - reservations-global + /// - reservations-in-subnet + /// - reservations-out-of-pool /// /// @param network_data Data element holding shared network /// configuration to be parsed. @@ -78,28 +94,6 @@ protected: void parseCacheParams(const data::ConstElementPtr& network_data, NetworkPtr& network); - /// @brief Parses host reservation mode. - /// - /// @note Configuring 'reservation-mode' is deprecated. The new - /// 'reservations-out-of-pool', 'reservations-in-subnet' and - /// 'reservations-global' parameters should be used. - /// - /// @param network_data Data element holding shared network - /// configuration to be parsed. - /// @param [out] network Pointer to a network in which parsed data is - /// to be stored. - void parseHostReservationMode(const data::ConstElementPtr& network_data, - NetworkPtr& network); - - /// @brief Parses host reservation modes. - /// - /// @param network_data Data element holding shared network - /// configuration to be parsed. - /// @param [out] network Pointer to a network in which parsed data is - /// to be stored. - void parseHostReservationModes(const data::ConstElementPtr& network_data, - NetworkPtr& network); - /// @brief Parses parameters pertaining to DDNS behavior. /// /// The parsed parameters are: diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index 2ce25deaef..72b8a8dd4d 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -743,9 +743,14 @@ Subnet4ConfigParser::initSubnet(data::ConstElementPtr params, subnet_id)); subnet_ = subnet4; + // Move from reservation mode to new reservations flags. + ElementPtr mutable_params; + mutable_params = boost::const_pointer_cast(params); + BaseNetworkParser::moveReservationMode(mutable_params); + // Parse parameters common to all Network derivations. NetworkPtr network = boost::dynamic_pointer_cast(subnet4); - parseCommon(params, network); + parseCommon(mutable_params, network); std::ostringstream output; output << addr << "/" << static_cast(len) << " with params: "; @@ -859,13 +864,6 @@ Subnet4ConfigParser::initSubnet(data::ConstElementPtr params, } } - // reservation modes - parseHostReservationModes(params, network); - - // Let's set host reservation mode. If not specified, the default value of - // all will be used. - parseHostReservationMode(params, network); - // Try setting up client class. if (params->contains("client-class")) { string client_class = getString(params, "client-class"); @@ -1241,9 +1239,14 @@ Subnet6ConfigParser::initSubnet(data::ConstElementPtr params, subnet_id); subnet_.reset(subnet6); + // Move from reservation mode to new reservations flags. + ElementPtr mutable_params; + mutable_params = boost::const_pointer_cast(params); + BaseNetworkParser::moveReservationMode(mutable_params); + // Parse parameters common to all Network derivations. NetworkPtr network = boost::dynamic_pointer_cast(subnet_); - parseCommon(params, network); + parseCommon(mutable_params, network); // Enable or disable Rapid Commit option support for the subnet. if (!rapid_commit.unspecified()) { @@ -1334,13 +1337,6 @@ Subnet6ConfigParser::initSubnet(data::ConstElementPtr params, subnet6->setIface(iface); } - // reservation modes - parseHostReservationModes(params, network); - - // Let's set host reservation mode. If not specified, the default value of - // all will be used. - parseHostReservationMode(params, network); - // Try setting up client class. if (params->contains("client-class")) { string client_class = getString(params, "client-class"); diff --git a/src/lib/dhcpsrv/parsers/shared_network_parser.cc b/src/lib/dhcpsrv/parsers/shared_network_parser.cc index 3248ede01f..729dbc02a6 100644 --- a/src/lib/dhcpsrv/parsers/shared_network_parser.cc +++ b/src/lib/dhcpsrv/parsers/shared_network_parser.cc @@ -44,9 +44,14 @@ SharedNetwork4Parser::parse(const data::ConstElementPtr& shared_network_data) { std::string name = getString(shared_network_data, "name"); shared_network.reset(new SharedNetwork4(name)); + // Move from reservation mode to new reservations flags. + ElementPtr mutable_params; + mutable_params = boost::const_pointer_cast(shared_network_data); + BaseNetworkParser::moveReservationMode(mutable_params); + // Parse parameters common to all Network derivations. NetworkPtr network = boost::dynamic_pointer_cast(shared_network); - parseCommon(shared_network_data, network); + parseCommon(mutable_params, network); // interface is an optional parameter if (shared_network_data->contains("interface")) { @@ -185,12 +190,6 @@ SharedNetwork4Parser::parse(const data::ConstElementPtr& shared_network_data) { } } - // reservation modes - parseHostReservationModes(shared_network_data, network); - - // reservation-mode - parseHostReservationMode(shared_network_data, network); - parseTeePercents(shared_network_data, network); // Parse DDNS parameters @@ -234,9 +233,14 @@ SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data) { std::string name = getString(shared_network_data, "name"); shared_network.reset(new SharedNetwork6(name)); + // Move from reservation mode to new reservations flags. + ElementPtr mutable_params; + mutable_params = boost::const_pointer_cast(shared_network_data); + BaseNetworkParser::moveReservationMode(mutable_params); + // Parse parameters common to all Network derivations. NetworkPtr network = boost::dynamic_pointer_cast(shared_network); - parseCommon(shared_network_data, network); + parseCommon(mutable_params, network); // preferred-lifetime shared_network->setPreferred(parseLifetime(shared_network_data, @@ -354,12 +358,6 @@ SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data) { } } - // reservation modes - parseHostReservationModes(shared_network_data, network); - - // reservation-mode - parseHostReservationMode(shared_network_data, network); - parseTeePercents(shared_network_data, network); // Parse DDNS parameters diff --git a/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc index 6adc4f27c7..445e5519b8 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc @@ -2905,6 +2905,7 @@ TEST_F(AllocEngine4Test, findReservation) { EXPECT_FALSE(ctx.currentHost()); // Check the out of the pool reservation mode. + subnet_->setReservationsInSubnet(true); subnet_->setReservationsOutOfPool(true); ASSERT_NO_THROW(engine.findReservation(ctx)); EXPECT_TRUE(ctx.currentHost()); diff --git a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc index df2956e07c..42397fef54 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc @@ -3719,6 +3719,7 @@ TEST_F(AllocEngine6Test, mixedHostReservedAddress) { subnet_->setReservationsGlobal(true); subnet_->setReservationsInSubnet(true); + subnet_->setReservationsOutOfPool(false); // Create context which will be used to try to allocate leases Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234)); @@ -3862,6 +3863,7 @@ TEST_F(AllocEngine6Test, bothHostReservedAddress) { subnet_->setReservationsGlobal(true); subnet_->setReservationsInSubnet(true); + subnet_->setReservationsOutOfPool(false); // Create context which will be used to try to allocate leases Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234)); diff --git a/src/lib/dhcpsrv/tests/network_unittest.cc b/src/lib/dhcpsrv/tests/network_unittest.cc index c9dc04b61f..7a3d89beff 100644 --- a/src/lib/dhcpsrv/tests/network_unittest.cc +++ b/src/lib/dhcpsrv/tests/network_unittest.cc @@ -6,9 +6,12 @@ #include #include +#include #include #include #include +#include +#include #include #include #include @@ -17,6 +20,7 @@ using namespace isc::asiolink; using namespace isc::data; using namespace isc::dhcp; using namespace isc::util; +using namespace isc::test; namespace { @@ -586,4 +590,155 @@ TEST_F(NetworkTest, getSiaddrNeverFail) { EXPECT_NO_THROW(net4_child->getSiaddr()); } +/// @brief Test fixture class for testing @c moveReservationMode. +class NetworkReservationTest : public ::testing::Test { +public: + + /// @brief Move test error case. + /// + /// Error cases of @ref BaseNetworkParser::moveReservationMode. + /// + /// @param config String with the config to test. + /// @param expected String with the expected error message. + void TestError(const std::string& config, const std::string& expected) { + ElementPtr cfg; + ASSERT_NO_THROW(cfg = Element::fromJSON(config)) + << "bad config, test broken"; + + ElementPtr copy = isc::data::copy(cfg); + + EXPECT_THROW_MSG(BaseNetworkParser::moveReservationMode(cfg), + DhcpConfigError, expected); + + ASSERT_TRUE(copy->equals(*cfg)); + } + + /// @brief Move test case. + /// + /// Test cases of @ref BaseNetworkParser::moveReservationMode. + /// + /// @param config String with the config to test. + /// @param expected String with the config after move. + void TestMove(const std::string& config, const std::string& expected) { + ElementPtr cfg; + ASSERT_NO_THROW(cfg = Element::fromJSON(config)) + << "bad config, test broken"; + + EXPECT_NO_THROW(BaseNetworkParser::moveReservationMode(cfg)); + + EXPECT_EQ(expected, cfg->str()); + } +}; + +/// @brief Test @ref BaseNetworkParser::moveReservationMode error cases. +TEST_F(NetworkReservationTest, errors) { + // Conflicts. + std::string config = "{\n" + "\"reservation-mode\": \"all\",\n" + "\"reservations-global\": true\n" + "}"; + std::string expected = "invalid use of both 'reservation-mode'" + " one of 'reservations-global', 'reservations-in-subnet'" + " or 'reservations-out-of-pool' parameters"; + TestError(config, expected); + + config = "{\n" + "\"reservation-mode\": \"all\",\n" + "\"reservations-in-subnet\": true\n" + "}"; + TestError(config, expected); + + config = "{\n" + "\"reservation-mode\": \"all\",\n" + "\"reservations-out-of-pool\": false\n" + "}"; + TestError(config, expected); + + // Unknown mode. + config = "{\n" + "\"reservation-mode\": \"foo\"\n" + "}"; + expected = "invalid reservation-mode parameter: 'foo' (:2:21)"; + TestError(config, expected); +} + +/// @brief Test @ref BaseNetworkParser::moveReservationMode. +TEST_F(NetworkReservationTest, move) { + // No-ops. + std::string config = "{\n" + "}"; + std::string expected = "{ " + " }"; + TestMove(config, expected); + + config = "{\n" + "\"reservations-global\": true\n" + "}"; + expected = "{" + " \"reservations-global\": true" + " }"; + TestMove(config, expected); + + // Disabled. + config = "{\n" + "\"reservation-mode\": \"disabled\"\n" + "}"; + expected = "{" + " \"reservations-global\": false," + " \"reservations-in-subnet\": false," + " \"reservations-out-of-pool\": false" + " }"; + TestMove(config, expected); + + config = "{\n" + "\"reservation-mode\": \"off\"\n" + "}"; + TestMove(config, expected); + + // Out-of-pool. + config = "{\n" + "\"reservation-mode\": \"out-of-pool\"\n" + "}"; + expected = "{" + " \"reservations-global\": false," + " \"reservations-in-subnet\": true," + " \"reservations-out-of-pool\": true" + " }"; + TestMove(config, expected); + + // Global. + config = "{\n" + "\"reservation-mode\": \"global\"\n" + "}"; + expected = "{" + " \"reservations-global\": true," + " \"reservations-in-subnet\": false," + " \"reservations-out-of-pool\": false" + " }"; + TestMove(config, expected); + + // All. + config = "{\n" + "\"reservation-mode\": \"all\"\n" + "}"; + expected = "{" + " \"reservations-global\": false," + " \"reservations-in-subnet\": true," + " \"reservations-out-of-pool\": false" + " }"; + TestMove(config, expected); + + config = "{\n" + "\"foobar\": 1234,\n" + "\"reservation-mode\": \"all\"\n" + "}"; + expected = "{" + " \"foobar\": 1234," + " \"reservations-global\": false," + " \"reservations-in-subnet\": true," + " \"reservations-out-of-pool\": false" + " }"; + TestMove(config, expected); +} + }