"item_default": 4000
},
+ { "item_name": "new-leases-on-renew",
+ "item_type": "boolean",
+ "item_optional": true,
+ "item_default": true
+ },
+
{ "item_name": "option-def",
"item_type": "list",
"item_optional": false,
ctx.ia_rsp_ = ia_rsp;
ctx.hwaddr_ = orig_ctx.hwaddr_;
ctx.host_ = orig_ctx.host_;
- ctx.allow_new_leases_in_renewals_ = true;
+ ctx.allow_new_leases_in_renewals_ = subnet->getAllocLeasesOnRenew();
// Extract the addresses that the client is trying to obtain.
OptionCollection addrs = ia->getOptions();
ctx.ia_rsp_ = ia_rsp;
ctx.hwaddr_ = orig_ctx.hwaddr_;
ctx.host_ = orig_ctx.host_;
- ctx.allow_new_leases_in_renewals_ = true;
+ ctx.allow_new_leases_in_renewals_ = subnet->getAllocLeasesOnRenew();
// Extract prefixes that the client is trying to renew.
OptionCollection addrs = ia->getOptions();
}
}
+ // Gather boolean parameters values.
bool rapid_commit = boolean_values_->getOptionalParam("rapid-commit", false);
+ bool alloc_leases_on_renew = globalContext()->
+ boolean_values_->getOptionalParam("new-leases-on-renew", true);
std::ostringstream output;
output << addr << "/" << static_cast<int>(len)
<< " with params t1=" << t1 << ", t2="
<< t2 << ", preferred-lifetime=" << pref
<< ", valid-lifetime=" << valid
- << ", rapid-commit is " << (rapid_commit ? "enabled" : "disabled");
+ << ", rapid-commit is " << (rapid_commit ? "enabled" : "disabled")
+ << ", new-leases-on-renew is " << (alloc_leases_on_renew ? "enabled" : "disabled");
+
LOG_INFO(dhcp6_logger, DHCP6_CONFIG_NEW_SUBNET).arg(output.str());
// Enable or disable Rapid Commit option support for the subnet.
subnet6->setRapidCommit(rapid_commit);
+ // Enable or disable allocation of the new leases for the Renew or/and Rebind message.
+ subnet6->setAllocLeasesOnRenew(alloc_leases_on_renew);
// Try setting up client class (if specified)
try {
parser = new RSOOListConfigParser(config_id);
} else if (config_id.compare("control-socket") == 0) {
parser = new ControlSocketParser(config_id);
+ } else if (config_id.compare("new-leases-on-renew") == 0) {
+ parser = new BooleanParser(config_id, globalContext()->boolean_values_);
} else {
isc_throw(DhcpConfigError,
"unsupported global configuration parameter: "
CfgMgr::instance().clear();
}
+ /// @brief Test the 'new-leases-on-renew' configuration flag.
+ ///
+ /// @param config Server configuration, possibly including the
+ /// 'new-leases-on-renew' parameter.
+ /// @param exp_alloc_leases_on_renew Expected value of the flag
+ void testAllocLeasesOnRenew(const std::string& config,
+ const bool exp_alloc_leases_on_renew) {
+ // Clear any existing configuration.
+ CfgMgr::instance().clear();
+
+ // Configure the server.
+ ElementPtr json = Element::fromJSON(config);
+
+ // Make sure that the configuration was successful.
+ ConstElementPtr status;
+ EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+ checkResult(status, 0);
+
+ // Get the subnet.
+ Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+ selectSubnet(IOAddress("2001:db8:1::5"), classify_);
+ ASSERT_TRUE(subnet);
+
+ // Check the flag against the expected value.
+ EXPECT_EQ(exp_alloc_leases_on_renew, subnet->getAllocLeasesOnRenew());
+
+ // Clear any existing configuration.
+ CfgMgr::instance().clear();
+ }
+
+
int rcode_; ///< Return code (see @ref isc::config::parseAnswer)
Dhcpv6Srv srv_; ///< Instance of the Dhcp6Srv used during tests
ConstElementPtr comment_; ///< Comment (see @ref isc::config::parseAnswer)
}
}
+// This test checks the configuration of the Rapid Commit option
+// support for the subnet.
+TEST_F(Dhcp6ParserTest, subnetAllocLeasesOnRenew) {
+ {
+ // new-leases-on-renew implicitly set to false.
+ SCOPED_TRACE("Default setting for new-leases-on-renew");
+ testAllocLeasesOnRenew("{ \"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::1 - "
+ "2001:db8:1::ffff\" } ],"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }",
+ true);
+ }
+
+ {
+ // new-leases-on-renew explicitly set to true.
+ SCOPED_TRACE("Enable new-leases-on-renew");
+ testAllocLeasesOnRenew("{ \"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"new-leases-on-renew\": True,"
+
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::1 - "
+ "2001:db8:1::ffff\" } ],"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }",
+ true);
+ }
+
+ {
+ // new-leases-on-renew explicitly set to false.
+ SCOPED_TRACE("Disable new-leases-on-renew");
+ testAllocLeasesOnRenew("{ \"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"new-leases-on-renew\": False,"
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::1 - "
+ "2001:db8:1::ffff\" } ],"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }",
+ false);
+ }
+}
+
// This test checks that multiple pools can be defined and handled properly.
// The test defines 2 subnets, each with 2 pools.
TEST_F(Dhcp6ParserTest, multiplePools) {
// Quick sanity check that the address we're about to use is ok
ASSERT_TRUE(subnet_->inPool(type, addr));
+ // Do not allocate leases as a result of Renew/Rebind.
+ subnet_->setAllocLeasesOnRenew(false);
+
// GenerateClientId() also sets duid_
OptionPtr clientid = generateClientId();
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
+ "\"new-leases-on-renew\": False,"
"\"subnet6\": [ { "
" \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
" \"subnet\": \"2001:db8:1::/48\", "
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
+ "\"new-leases-on-renew\": False,"
"\"subnet6\": [ { "
" \"pools\": [ { \"pool\": \"2001:db8:3::/64\" } ],"
" \"subnet\": \"2001:db8:3::/48\", "
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
+ "\"new-leases-on-renew\": False,"
"\"subnet6\": [ { "
" \"pools\": [ { \"pool\": \"3000:1::/64\" } ],"
" \"subnet\": \"3000:1::/48\", "
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
+ "\"new-leases-on-renew\": False,"
"\"subnet6\": [ { "
" \"pools\": [ { \"pool\": \"3000:3::/64\" } ],"
" \"subnet\": \"3000:3::/48\", "
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
+ "\"new-leases-on-renew\": False,"
"\"subnet6\": [ { "
" \"pd-pools\": ["
" { \"prefix\": \"3000::\", "
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
+ "\"new-leases-on-renew\": False,"
"\"subnet6\": [ { "
" \"pd-pools\": ["
" { \"prefix\": \"2001:db8:3:01::\", "
const Triplet<uint32_t>& valid_lifetime,
const SubnetID id)
:Subnet(prefix, length, t1, t2, valid_lifetime, RelayInfo(IOAddress("::")), id),
- preferred_(preferred_lifetime), rapid_commit_(false) {
+ preferred_(preferred_lifetime), rapid_commit_(false),
+ alloc_leases_on_renew_(true) {
if (!prefix.isV6()) {
isc_throw(BadValue, "Non IPv6 prefix " << prefix
<< " specified in subnet6");
return (rapid_commit_);
}
+ /// @brief Enables or disables the allocation of the new leases for the
+ /// Renew and Rebind case.
+ ///
+ /// @param alloc_leases_on_renew A boolean value indicating if the server
+ /// can allocate new leases for the Renew and Rebind case.
+ void setAllocLeasesOnRenew(const bool alloc_leases_on_renew) {
+ alloc_leases_on_renew_ = alloc_leases_on_renew;
+ }
+
+ /// @brief Returns boolean value indicating if the new leases are allocated
+ /// by the server as a result of processing Renew and/or Rebind.
+ bool getAllocLeasesOnRenew() const {
+ return (alloc_leases_on_renew_);
+ }
+
private:
/// @brief Returns default address for pool selection
/// It's default value is false, which indicates that the Rapid
/// Commit is disabled for the subnet.
bool rapid_commit_;
+
+ /// @brief A flag indicating if the server may allocate new leases
+ /// for the client sending a Renew or Rebind message.
+ ///
+ /// This flag indicates that the client may request allocation of the
+ /// new leases (of any type) when it renews existing leases. This
+ /// facilitates the use cases described in RFC7550. If the server is
+ /// configured to allocate new leases for the Renew and Rebind case
+ /// but it can't allocate them (e.g. because of the pool exhaustion)
+ /// it will send the NoAddrsAvail or the NoPrefixAvail status code
+ /// in the IA, depending on the IA type.
+ bool alloc_leases_on_renew_;
};
/// @brief A pointer to a Subnet6 object
EXPECT_FALSE(subnet.getRapidCommit());
}
+// This test checks that the flag which indicates if the new leases are
+// allocated as a result of processing the Renew and Rebind message can
+// be set to "enable" or "disable".
+TEST(Subnet6Test, allocNewLeasesOnRenew) {
+ Subnet6 subnet(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4);
+
+ // By default, the flag should be enabled.
+ EXPECT_TRUE(subnet.getAllocLeasesOnRenew());
+
+ // Disable it.
+ subnet.setAllocLeasesOnRenew(false);
+ EXPECT_FALSE(subnet.getAllocLeasesOnRenew());
+
+ // Enable again.
+ subnet.setAllocLeasesOnRenew(true);
+ EXPECT_TRUE(subnet.getAllocLeasesOnRenew());
+}
+
// Checks if last allocated address/prefix is stored/retrieved properly
TEST(Subnet6Test, lastAllocated) {
IOAddress ia("2001:db8:1::1");