Commit ddb442f7 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[3947] Removed the new-leases-on-renew config parameter.

This change removes ability to disable allocation new leases new
Renew/Rebind, specified in RFC7550. The behavior specified in this
RFC is the only supported behavior.
parent 623693cd
......@@ -62,12 +62,6 @@
"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,
......
......@@ -224,24 +224,6 @@ as a result of receiving SIGHUP signal.
This is an error message logged when the dynamic reconfiguration of the
DHCP server failed.
% DHCP6_EXTEND_NA_UNKNOWN %1: received unknown IA_NA with iaid=%2 in subnet %3
This warning message is printed when client attempts to extend the lease
for the address (in the IA_NA option) but no such lease is known by the server.
It typically means that client has attempted to use its lease past its
lifetime: causes of this include a adjustment of the client's date/time
setting or poor support on the client for sleep/recovery. A properly
implemented client will recover from such a situation by restarting the
lease allocation process after receiving a negative reply from the server.
The first argument includes the client and the transaction identification
information. The second argument holds IAID. The third argument holds the
subnet information.
An alternative cause could be that the server has lost its database
recently and does not recognize its well-behaving clients. This is more
probable if you see many such messages. Clients will recover from this,
but they will most likely get a different IP addresses and experience
a brief service interruption.
% DHCP6_HOOKS_LIBS_RELOAD_FAIL reload of hooks libraries failed
A "libreload" command was issued to reload the hooks libraries but for
some reason the reload failed. Other error messages issued from the
......
......@@ -1721,7 +1721,6 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer,
ctx.ia_rsp_ = ia_rsp;
ctx.hwaddr_ = orig_ctx.hwaddr_;
ctx.host_ = orig_ctx.host_;
ctx.allow_new_leases_in_renewals_ = subnet->getAllocLeasesOnRenew();
// Extract the addresses that the client is trying to obtain.
OptionCollection addrs = ia->getOptions();
......@@ -1802,34 +1801,12 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer,
// All is left is to insert the status code.
if (leases.empty()) {
// We did not assign any address to the client. Depending on whether the
// server is configured to allocate new leases during the Renew or
// Rebind we will have to send a different status code. If the server
// is configured to allocate new leases for the Renew and Rebind, the
// status code will be NoAddressAvail. If the server is not configured
// to allocate prefixes for the renewing client, the status code will
// be NoBinding, or perhaps the message will be dropped if this is the
// Rebind case.
if (!subnet->getAllocLeasesOnRenew()) {
ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_NoBinding,
"Sorry, no known NA leases for"
" this duid/iaid/subnet."));
LOG_DEBUG(lease_logger, DBG_DHCP6_DETAIL, DHCP6_EXTEND_NA_UNKNOWN)
.arg(query->getLabel())
.arg(ia->getIAID())
.arg(subnet->toText());
} else {
// The server is configured to allocate new leases for the
// renewing client, but it could not allocate anything at this
// time. The status code should be NoAddrsAvail, per RFC7550.
ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_NoAddrsAvail,
"Sorry, no addresses could be"
" assigned at this time."));
}
// The server wasn't able allocate new lease and renew an exising
// lease. In that case, the server sends NoAddrsAvail per RFC7550.
ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_NoAddrsAvail,
"Sorry, no addresses could be"
" assigned at this time."));
}
return (ia_rsp);
......@@ -1894,7 +1871,6 @@ Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query,
ctx.ia_rsp_ = ia_rsp;
ctx.hwaddr_ = orig_ctx.hwaddr_;
ctx.host_ = orig_ctx.host_;
ctx.allow_new_leases_in_renewals_ = subnet->getAllocLeasesOnRenew();
// Extract prefixes that the client is trying to renew.
OptionCollection addrs = ia->getOptions();
......@@ -1963,47 +1939,12 @@ Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query,
// All is left is to insert the status code.
if (leases.empty()) {
// We did not assign any prefix to the client. Depending on whether the
// server is configured to allocate new leases during the Renew or
// Rebind we will have to send a different status code. If the server
// is configured to allocate new leases for the Renew and Rebind, the
// status code will be NoPrefixAvail. If the server is not configured
// to allocate prefixes for the renewing client, the status code will
// be NoBinding, or perhaps the message will be dropped if this is the
// Rebind case.
if (!subnet->getAllocLeasesOnRenew()) {
// The server is not configured to allocate new leases, so return
// the NoBinding for the Renew, and drop the message for the
// Rebind. There is also a detailed comment for the Rebind case
// further on.
if (query->getType() == DHCPV6_RENEW) {
ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_NoBinding,
"Sorry, no known PD leases for"
" this duid/iaid/subnet."));
} else {
// Per RFC3633, section 12.2, if there is no binding and we are
// processing Rebind, the message has to be discarded (assuming that
// the server doesn't know if the prefix in the IA_PD option is
// appropriate for the client's link). The exception being thrown
// here should propagate to the main loop and cause the message to
// be discarded.
isc_throw(DHCPv6DiscardMessageError, "no binding found for the"
" DUID=" << duid->toText() << ", IAID="
<< ia->getIAID() << ", subnet="
<< subnet->toText() << " when processing a Rebind"
" message with IA_PD option");
}
} else {
// The server is configured to allocate new leases for the
// renewing client, but it could not allocate anything at this
// time. The status code should be NoPrefixAvail, per RFC7550.
ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_NoPrefixAvail,
"Sorry, no prefixes could be"
" assigned at this time."));
}
// The server wasn't able allocate new lease and renew an exising
// lease. In that case, the server sends NoPrefixAvail per RFC7550.
ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_NoPrefixAvail,
"Sorry, no prefixes could be"
" assigned at this time."));
}
return (ia_rsp);
......
......@@ -475,16 +475,13 @@ protected:
// 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")
<< ", new-leases-on-renew is " << (alloc_leases_on_renew ? "enabled" : "disabled");
<< ", rapid-commit is " << (rapid_commit ? "enabled" : "disabled");
LOG_INFO(dhcp6_logger, DHCP6_CONFIG_NEW_SUBNET).arg(output.str());
......@@ -502,8 +499,6 @@ protected:
// 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 {
......@@ -700,8 +695,6 @@ namespace dhcp {
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: "
......
......@@ -531,37 +531,6 @@ public:
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)
......@@ -1203,55 +1172,6 @@ TEST_F(Dhcp6ParserTest, subnetRapidCommit) {
}
}
// 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) {
......
......@@ -94,7 +94,9 @@ Dhcp6Client::Dhcp6Client() :
use_rapid_commit_(false),
address_hint_(),
prefix_hint_(),
fqdn_() {
fqdn_(),
na_iaid_(1234),
pd_iaid_(5678) {
}
Dhcp6Client::Dhcp6Client(boost::shared_ptr<NakedDhcpv6Srv>& srv) :
......@@ -113,7 +115,9 @@ Dhcp6Client::Dhcp6Client(boost::shared_ptr<NakedDhcpv6Srv>& srv) :
use_rapid_commit_(false),
address_hint_(),
prefix_hint_(),
fqdn_() {
fqdn_(),
na_iaid_(1234),
pd_iaid_(5678) {
}
void
......@@ -243,11 +247,11 @@ Dhcp6Client::appendFQDN() {
void
Dhcp6Client::appendRequestedIAs(const Pkt6Ptr& query) const {
if (use_na_) {
conditionallyAppendRequestedIA(query, D6O_IA_NA, 1234);
conditionallyAppendRequestedIA(query, D6O_IA_NA, na_iaid_);
}
if (use_pd_) {
conditionallyAppendRequestedIA(query, D6O_IA_PD, 5678);
conditionallyAppendRequestedIA(query, D6O_IA_PD, pd_iaid_);
}
}
......@@ -445,9 +449,9 @@ Dhcp6Client::doInfRequest() {
// IA_NA, IA_TA and IA_PD options are not allowed in INF-REQUEST,
// but hey! Let's test it.
if (use_na_) {
// Insert IA_NA option with iaid=1234.
// Insert IA_NA option.
context_.query_->addOption(Option6IAPtr(new Option6IA(D6O_IA_NA,
1234)));
na_iaid_)));
}
// IA-PD is also not allowed. So it may be useful in testing, too.
......
......@@ -439,8 +439,10 @@ public:
///
/// @param use Parameter which 'true' value indicates that client should
/// request address assignment.
void useNA(const bool use = true) {
/// @param iaid IAID to be used in the IA_NA.
void useNA(const bool use = true, const uint32_t iaid = 1234) {
use_na_ = use;
na_iaid_ = iaid;
}
/// @brief Place IA_PD options to request prefix assignment.
......@@ -450,8 +452,10 @@ public:
///
/// @param use Parameter which 'true' value indicates that client should
/// request prefix assignment.
void usePD(const bool use = true) {
/// @param iaid IAID to be used in the IA_NA.
void usePD(const bool use = true, const uint32_t iaid = 5678) {
use_pd_ = use;
pd_iaid_ = iaid;
}
/// @brief Simulate sending messages through a relay.
......@@ -706,6 +710,11 @@ private:
/// @brief FQDN requested by the client.
Option6ClientFqdnPtr fqdn_;
/// @bref IAID used by the client when requesting address assignment.
uint32_t na_iaid_;
/// @brief IAID used by the client when requesting prefix delegation.
uint32_t pd_iaid_;
};
} // end of namespace isc::dhcp::test
......
......@@ -939,23 +939,6 @@ TEST_F(Dhcpv6SrvTest, RenewSomeoneElesesLease) {
testRenewSomeoneElsesLease(Lease::TYPE_NA, IOAddress("2001:db8::1"));
}
// This test verifies that incoming (invalid) RENEW with a prefix
// can be handled properly.
//
// This test checks 3 scenarios:
// 1. there is no such lease at all
// 2. there is such a lease, but it is assigned to a different IAID
// 3. there is such a lease, but it belongs to a different client
//
// expected:
// - returned REPLY message has copy of client-id
// - returned REPLY message has server-id
// - returned REPLY message has IA_PD that includes STATUS-CODE
// - No lease in LeaseMgr
TEST_F(Dhcpv6SrvTest, pdRenewReject) {
testRenewReject(Lease::TYPE_PD, IOAddress("2001:db8:1:2::"));
}
// This test verifies that incoming (positive) RELEASE with address can be
// handled properly, that a REPLY is generated, that the response has status
// code and that the lease is indeed removed from the database.
......
......@@ -420,149 +420,6 @@ Dhcpv6SrvTest::testRenewSomeoneElsesLease(Lease::Type type, const IOAddress& add
ASSERT_TRUE(l);
}
void
Dhcpv6SrvTest::testRenewReject(Lease::Type type, const IOAddress& addr) {
NakedDhcpv6Srv srv(0);
const uint32_t transid = 1234;
const uint32_t valid_iaid = 234;
const uint32_t bogus_iaid = 456;
uint32_t code;
uint8_t prefix_len;
if (type == Lease::TYPE_NA) {
code = D6O_IA_NA;
prefix_len = 128;
} else if (type == Lease::TYPE_PD) {
code = D6O_IA_PD;
prefix_len = pd_pool_->getLength();
} else {
isc_throw(BadValue, "Invalid lease type");
}
// 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();
// Check that the lease is NOT in the database
Lease6Ptr l = LeaseMgrFactory::instance().getLease6(type, addr);
ASSERT_FALSE(l);
// Let's create a RENEW
Pkt6Ptr req = createMessage(DHCPV6_RENEW, type, IOAddress(addr), prefix_len,
bogus_iaid);
req->addOption(clientid);
req->addOption(srv.getServerID());
// Case 1: No lease known to server
// Pass it to the server and hope for a REPLY
Pkt6Ptr reply = srv.processRenew(req);
// Check if we get response at all
checkResponse(reply, DHCPV6_REPLY, transid);
OptionPtr tmp = reply->getOption(code);
ASSERT_TRUE(tmp);
// Check that IA_?? was returned and that there's proper status code
boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
ASSERT_TRUE(ia);
if (type == Lease::TYPE_PD) {
// For PD, the check is easy. NoBinding and no prefixes
checkIA_NAStatusCode(ia, STATUS_NoBinding, subnet_->getT1(), subnet_->getT2());
} else {
// For IA, it's more involved, as the server will reject the address
// (and send it with 0 lifetimes), but will also assign a new address.
// First, check that the requested address is rejected.
bool found = false;
dhcp::OptionCollection options = ia->getOptions();
for (isc::dhcp::OptionCollection::iterator opt = options.begin();
opt != options.end(); ++opt) {
if (opt->second->getType() != D6O_IAADDR) {
continue;
}
dhcp::Option6IAAddrPtr opt_addr =
boost::dynamic_pointer_cast<isc::dhcp::Option6IAAddr>(opt->second);
ASSERT_TRUE(opt_addr);
if (opt_addr->getAddress() != addr) {
// There may be other addresses, e.g. the newly assigned one
continue;
}
found = true;
EXPECT_NE(0, opt_addr->getPreferred());
EXPECT_NE(0, opt_addr->getValid());
}
EXPECT_TRUE(found) << "Expected address " << addr.toText()
<< " with zero lifetimes not found.";
}
// Check that there is no lease added
l = LeaseMgrFactory::instance().getLease6(type, addr);
ASSERT_FALSE(l);
// CASE 2: Lease is known and belongs to this client, but to a different IAID
// Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
// value on purpose. They should be updated during RENEW.
Lease6Ptr lease(new Lease6(type, addr, duid_, valid_iaid,
501, 502, 503, 504, subnet_->getID(),
HWAddrPtr(), prefix_len));
lease->cltt_ = 123; // Let's use it as an indicator that the lease
// was NOT updated.
ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
// Pass it to the server and hope for a REPLY
reply = srv.processRenew(req);
checkResponse(reply, DHCPV6_REPLY, transid);
tmp = reply->getOption(code);
ASSERT_TRUE(tmp);
// Check that IA_?? was returned and that there's proper status code
ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
ASSERT_TRUE(ia);
checkIA_NAStatusCode(ia, STATUS_NoBinding, subnet_->getT1(), subnet_->getT2());
// There is a iaid mis-match, so server should respond that there is
// no such address to renew.
// CASE 3: Lease belongs to a client with different client-id
req->delOption(D6O_CLIENTID);
ia = boost::dynamic_pointer_cast<Option6IA>(req->getOption(code));
ia->setIAID(valid_iaid); // Now iaid in renew matches that in leasemgr
req->addOption(generateClientId(13)); // generate different DUID
// (with length 13)
reply = srv.processRenew(req);
checkResponse(reply, DHCPV6_REPLY, transid);
tmp = reply->getOption(code);
ASSERT_TRUE(tmp);
// Check that IA_?? was returned and that there's proper status code
ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
ASSERT_TRUE(ia);
checkIA_NAStatusCode(ia, STATUS_NoBinding, subnet_->getT1(), subnet_->getT2());
lease = LeaseMgrFactory::instance().getLease6(type, addr);
ASSERT_TRUE(lease);
// Verify that the lease was not updated.
EXPECT_EQ(123, lease->cltt_);
EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
}
void
Dhcpv6SrvTest::testReleaseBasic(Lease::Type type, const IOAddress& existing,
const IOAddress& release_addr) {
......
......@@ -468,19 +468,6 @@ public:
testRenewSomeoneElsesLease(isc::dhcp::Lease::Type type,
const asiolink::IOAddress& addr);
/// @brief Performs negative RENEW test
///
/// See renewReject and pdRenewReject tests for detailed explanation.
/// In essence the test attempts to perform couple failed RENEW scenarios.
///
/// This method does not throw, but uses gtest macros to signify failures.
///
/// @param type type (TYPE_NA or TYPE_PD)
/// @param addr address being sent in RENEW
void
testRenewReject(isc::dhcp::Lease::Type type,
const isc::asiolink::IOAddress& addr);
/// @brief Performs basic (positive) RELEASE test
///
/// See releaseBasic and pdReleaseBasic tests for detailed explanation.
......
This diff is collapsed.
......@@ -44,23 +44,6 @@ namespace {
/// - address pool: 2001:db8:1::/64
/// - prefix pool: 3000::/72
///
/// - Configuration 3:
/// - only addresses (no prefixes)
/// - 1 subnet with 2001:db8:1::/64 pool
/// - 'new-leases-on-renew' disabled
///
/// - Configuration 4:
/// - only prefixes (no addresses)
/// - prefix pool: 3000::/72
/// - 'new-leases-on-renew' disabled
///
/// - Configuration 5:
/// - addresses and prefixes
/// - 1 subnet with one address pool and one prefix pool
/// - address pool: 2001:db8:1::/64
/// - prefix pool: 3000::/72
/// - 'new-leases-on-renew' disabled
///
const char* RENEW_CONFIGS[] = {
// Configuration 0
"{ \"interfaces-config\": {"
......@@ -114,63 +97,6 @@ const char* RENEW_CONFIGS[] = {
" \"interface-id\": \"\","
" \"interface\": \"eth0\""
" } ],"
"\"valid-lifetime\": 4000 }",
// Configuration 3
"{ \"interfaces-config\": {"
" \"interfaces\": [ \"*\" ]"
"},"
"\"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\", "
" \"interface-id\": \"\","
" \"interface\": \"eth0\""
" } ],"
"\"valid-lifetime\": 4000 }",