Commit 9ce50790 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[master] Merge branch 'trac3677' (DHCPv6 renewals with reservations)

Conflicts:
	src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
parents b7407dd5 a339db38
# Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
# Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
......@@ -91,8 +91,7 @@ to perform the DNS Update, which removes RRs from the DNS.
This debug message is logged when FQDN mapping for a particular lease has
been changed by the recent Request message. This mapping will be changed in DNS.
% DHCP6_DDNS_LEASE_RENEW_FQDN_CHANGE FQDN for the renewed lease: %1 has changed
New values: hostname = %2, reverse mapping = %3, forward mapping = %4
% DHCP6_DDNS_LEASE_RENEW_FQDN_CHANGE FQDN for the renewed lease: %1 has changed. New values: hostname = %2, reverse mapping = %3, forward mapping = %4
This debug message is logged when FQDN mapping for a particular lease has been
changed by the recent Renew message. This mapping will be changed in DNS.
......
This diff is collapsed.
// Copyright (C) 2011-2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
......@@ -667,6 +667,21 @@ private:
/// as a programmatic error.
void generateFqdn(const Pkt6Ptr& answer);
/// @brief Triggers removal Name Change Request if FQDN data changes in leases
///
/// If there are any differences (different fwd or rev flags, or different
/// hostname) a DNS update for removing entry will be generated.
///
/// @param old_lease old version of the lease
/// @param new_lease new version of the lease (may be NULL)
/// @param hostname specifies hostname (for printing purposes)
/// @param do_fwd specifies if reverse updates are enabled (for printing purposes)
/// @param do_rev specifies if reverse updates are enabled (for printing purposes)
void conditionalNCRRemoval(Lease6Ptr& old_lease, Lease6Ptr& new_lease,
const std::string& hostname,
bool do_fwd, bool do_rev);
/// @brief Allocation Engine.
/// Pointer to the allocation engine that we are currently using
/// It must be a pointer, because we will support changing engines
......
......@@ -88,7 +88,8 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
case D6O_IAADDR:
{
Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<
Option6IAAddr>(ia->getOption(D6O_IAADDR));
Option6IAAddr>(ia_opt);
if (!iaaddr) {
// There is no address. This IA option may simply
// contain a status code, so let's just reset the
......@@ -113,7 +114,7 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
case D6O_IAPREFIX:
{
Option6IAPrefixPtr iaprefix = boost::dynamic_pointer_cast<
Option6IAPrefix>(ia->getOption(D6O_IAPREFIX));
Option6IAPrefix>(ia_opt);
if (!iaprefix) {
// There is no prefix. This IA option may simply
// contain a status code, so let's just reset the
......
......@@ -406,6 +406,12 @@ public:
oro_.push_back(option_code);
}
/// @brief returns client-id
/// @return client-id
DuidPtr getDuid() const {
return (duid_);
}
private:
/// @brief Applies the new leases for the client.
......
......@@ -81,7 +81,8 @@ TEST_F(NakedDhcpv6SrvTest, SolicitNoSubnet) {
Pkt6Ptr reply = srv.processSolicit(sol);
// check that we get the right NAK
checkNakResponse (reply, DHCPV6_ADVERTISE, 1234, STATUS_NoAddrsAvail);
checkNakResponse(reply, DHCPV6_ADVERTISE, 1234, STATUS_NoAddrsAvail,
0, 0);
}
// This test verifies that incoming REQUEST can be handled properly when
......@@ -113,7 +114,8 @@ TEST_F(NakedDhcpv6SrvTest, RequestNoSubnet) {
Pkt6Ptr reply = srv.processRequest(req);
// check that we get the right NAK
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoAddrsAvail);
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoAddrsAvail,
0, 0);
}
// This test verifies that incoming RENEW can be handled properly, even when
......@@ -148,7 +150,8 @@ TEST_F(NakedDhcpv6SrvTest, RenewNoSubnet) {
Pkt6Ptr reply = srv.processRenew(req);
// check that we get the right NAK
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding);
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding,
0, 0);
}
// This test verifies that incoming RELEASE can be handled properly, even when
......@@ -183,7 +186,7 @@ TEST_F(NakedDhcpv6SrvTest, ReleaseNoSubnet) {
Pkt6Ptr reply = srv.processRelease(req);
// check that we get the right NAK
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding);
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding, 0, 0);
}
// Test verifies that the Dhcpv6_srv class can be instantiated. It checks a mode
......
......@@ -285,10 +285,10 @@ Dhcpv6SrvTest::testRenewBasic(Lease::Type type, const std::string& existing_addr
}
// Check that T1, T2, preferred, valid and cltt were really updated
EXPECT_EQ(l->t1_, subnet_->getT1());
EXPECT_EQ(l->t2_, subnet_->getT2());
EXPECT_EQ(l->preferred_lft_, subnet_->getPreferred());
EXPECT_EQ(l->valid_lft_, subnet_->getValid());
EXPECT_EQ(subnet_->getT1(), l->t1_);
EXPECT_EQ(subnet_->getT2(), l->t2_);
EXPECT_EQ(subnet_->getPreferred(), l->preferred_lft_);
EXPECT_EQ(subnet_->getValid(), l->valid_lft_);
// Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
int32_t cltt = static_cast<int32_t>(l->cltt_);
......@@ -349,7 +349,7 @@ Dhcpv6SrvTest::testRenewReject(Lease::Type type, const IOAddress& addr) {
// 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);
checkIA_NAStatusCode(ia, STATUS_NoBinding);
checkIA_NAStatusCode(ia, STATUS_NoBinding, subnet_->getT1(), subnet_->getT2());
// Check that there is no lease added
l = LeaseMgrFactory::instance().getLease6(type, addr);
......@@ -375,7 +375,7 @@ Dhcpv6SrvTest::testRenewReject(Lease::Type type, const IOAddress& addr) {
// 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);
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.
......@@ -395,7 +395,7 @@ Dhcpv6SrvTest::testRenewReject(Lease::Type type, const IOAddress& addr) {
// 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);
checkIA_NAStatusCode(ia, STATUS_NoBinding, subnet_->getT1(), subnet_->getT2());
lease = LeaseMgrFactory::instance().getLease6(type, addr);
ASSERT_TRUE(lease);
......@@ -457,7 +457,7 @@ Dhcpv6SrvTest::testReleaseBasic(Lease::Type type, const IOAddress& existing,
// Check that IA_NA was returned and that there's an address included
boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
checkIA_NAStatusCode(ia, STATUS_Success);
checkIA_NAStatusCode(ia, STATUS_Success, 0, 0);
checkMsgStatusCode(reply, STATUS_Success);
// There should be no address returned in RELEASE (see RFC3315, 18.2.6)
......@@ -528,7 +528,7 @@ Dhcpv6SrvTest::testReleaseReject(Lease::Type type, const IOAddress& addr) {
// Check that IA_NA/IA_PD was returned and that there's status code in it
boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
ASSERT_TRUE(ia);
checkIA_NAStatusCode(ia, STATUS_NoBinding);
checkIA_NAStatusCode(ia, STATUS_NoBinding, 0, 0);
checkMsgStatusCode(reply, STATUS_NoBinding);
// Check that the lease is not there
......@@ -556,7 +556,7 @@ Dhcpv6SrvTest::testReleaseReject(Lease::Type type, const IOAddress& addr) {
// 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);
checkIA_NAStatusCode(ia, STATUS_NoBinding, 0, 0);
checkMsgStatusCode(reply, STATUS_NoBinding);
// Check that the lease is still there
......@@ -580,7 +580,7 @@ Dhcpv6SrvTest::testReleaseReject(Lease::Type type, const IOAddress& addr) {
// 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);
checkIA_NAStatusCode(ia, STATUS_NoBinding, 0, 0);
checkMsgStatusCode(reply, STATUS_NoBinding);
// Check that the lease is still there
......@@ -651,6 +651,56 @@ Dhcpv6SrvTest::compareOptions(const isc::dhcp::OptionPtr& option1,
return (!memcmp(buf1.getData(), buf2.getData(), buf1.getLength()));
}
void
NakedDhcpv6SrvTest::checkIA_NAStatusCode(
const boost::shared_ptr<isc::dhcp::Option6IA>& ia,
uint16_t expected_status_code, uint32_t expected_t1, uint32_t expected_t2)
{
// Make sure there is no address assigned. Depending on the situation,
// the server will either not return the address at all and sometimes
// it will return it with zeroed lifetimes.
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 addr =
boost::dynamic_pointer_cast<isc::dhcp::Option6IAAddr>(opt->second);
ASSERT_TRUE(addr);
EXPECT_EQ(0, addr->getPreferred());
EXPECT_EQ(0, addr->getValid());
}
// T1, T2 should NOT be zeroed. draft-ietf-dhc-dhcpv6-stateful-issues-10,
// section 4.4.6 says says that T1,T2 should be consistent along all
// provided IA options.
EXPECT_EQ(expected_t1, ia->getT1());
EXPECT_EQ(expected_t2, ia->getT2());
isc::dhcp::OptionCustomPtr status =
boost::dynamic_pointer_cast<isc::dhcp::OptionCustom>
(ia->getOption(D6O_STATUS_CODE));
// It is ok to not include status success as this is the default
// behavior
if (expected_status_code == STATUS_Success && !status) {
return;
}
EXPECT_TRUE(status);
if (status) {
// We don't have dedicated class for status code, so let's
// just interpret first 2 bytes as status. Remainder of the
// status code option content is just a text explanation
// what went wrong.
EXPECT_EQ(static_cast<uint16_t>(expected_status_code),
status->readInteger<uint16_t>(0));
}
}
}; // end of isc::test namespace
}; // end of isc namespace
......@@ -27,6 +27,7 @@
#include <dhcp/option6_iaprefix.h>
#include <dhcp/option_int_array.h>
#include <dhcp/option_custom.h>
#include <dhcp/option.h>
#include <dhcp/iface_mgr.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease_mgr.h>
......@@ -211,7 +212,8 @@ public:
void checkNakResponse(const isc::dhcp::Pkt6Ptr& rsp,
uint8_t expected_message_type,
uint32_t expected_transid,
uint16_t expected_status_code)
uint16_t expected_status_code,
uint32_t expected_t1, uint32_t expected_t2)
{
// Check if we get response at all
checkResponse(rsp, expected_message_type, expected_transid);
......@@ -225,7 +227,8 @@ public:
boost::dynamic_pointer_cast<isc::dhcp::Option6IA>(option_ia_na);
ASSERT_TRUE(ia);
checkIA_NAStatusCode(ia, expected_status_code);
checkIA_NAStatusCode(ia, expected_status_code, expected_t1,
expected_t2);
}
// Checks that server rejected IA_NA, i.e. that it has no addresses and
......@@ -238,36 +241,8 @@ public:
// as this is the default result and it saves bandwidth)
void checkIA_NAStatusCode
(const boost::shared_ptr<isc::dhcp::Option6IA>& ia,
uint16_t expected_status_code)
{
// Make sure there is no address assigned.
EXPECT_FALSE(ia->getOption(D6O_IAADDR));
// T1, T2 should be zeroed
EXPECT_EQ(0, ia->getT1());
EXPECT_EQ(0, ia->getT2());
isc::dhcp::OptionCustomPtr status =
boost::dynamic_pointer_cast<isc::dhcp::OptionCustom>
(ia->getOption(D6O_STATUS_CODE));
// It is ok to not include status success as this is the default
// behavior
if (expected_status_code == STATUS_Success && !status) {
return;
}
EXPECT_TRUE(status);
if (status) {
// We don't have dedicated class for status code, so let's
// just interpret first 2 bytes as status. Remainder of the
// status code option content is just a text explanation
// what went wrong.
EXPECT_EQ(static_cast<uint16_t>(expected_status_code),
status->readInteger<uint16_t>(0));
}
}
uint16_t expected_status_code, uint32_t expected_t1,
uint32_t expected_t2);
void checkMsgStatusCode(const isc::dhcp::Pkt6Ptr& msg,
uint16_t expected_status)
......@@ -397,8 +372,8 @@ public:
// an ostream, which means it can't be used in EXPECT_EQ.
EXPECT_TRUE(subnet_->inPool(type, addr->getAddress()));
EXPECT_EQ(expected_addr.toText(), addr->getAddress().toText());
EXPECT_EQ(addr->getPreferred(), subnet_->getPreferred());
EXPECT_EQ(addr->getValid(), subnet_->getValid());
EXPECT_EQ(subnet_->getPreferred(), addr->getPreferred());
EXPECT_EQ(subnet_->getValid(), addr->getValid());
}
// Checks if the lease sent to client is present in the database
......
// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
......@@ -414,7 +414,7 @@ public:
ASSERT_NO_THROW(reply = srv_->processRequest(req));
} else if (msg_type == DHCPV6_RENEW) {
ASSERT_NO_THROW(reply = srv_->processRequest(req));
ASSERT_NO_THROW(reply = srv_->processRenew(req));
} else if (msg_type == DHCPV6_RELEASE) {
// For Release no lease will be acquired so we have to leave
......
......@@ -262,15 +262,21 @@ TEST_F(RebindTest, directClientChangingSubnet) {
configure(REBIND_CONFIGS[1], *client.getServer());
// Try to rebind, using the address that the client had acquired using
// previous server configuration.
ASSERT_NO_THROW(client.doRebind());
// We are expecting that the server didn't extend the lease because
// the address that client is using doesn't match the new subnet.
// But, the client still has an old lease.
ASSERT_EQ(1, client.getLeaseNum());
Lease6 lease_client2 = client.getLease(0);
// The current lease should be exactly the same as old lease,
// because server shouldn't have extended.
EXPECT_TRUE(lease_client == lease_client2);
EXPECT_TRUE(lease_client.addr_ == lease_client2.addr_);
EXPECT_EQ(0, lease_client2.preferred_lft_);
EXPECT_EQ(0, lease_client2.valid_lft_);
// Make sure, that the lease that client has, is matching the lease
// in the lease database.
Lease6Ptr lease_server2 = checkLease(lease_client2);
......@@ -480,13 +486,31 @@ TEST_F(RebindTest, relayedClientChangingAddress) {
<< "The server discarded the Rebind message, while it should have"
" sent a response indicating that the client should stop using the"
" lease, by setting lifetime values to 0.";
// Get the client's lease.
ASSERT_EQ(1, client.getLeaseNum());
Lease6 lease_client2 = client.getLease(0);
// Get the client's leases. He should get two addresses:
// the first one for the bogus 3000::100 address with 0 lifetimes.
// the second one with the actual lease with non-zero lifetimes.
ASSERT_EQ(2, client.getLeaseNum());
// Let's check the first one
Lease6 lease_client1 = client.getLease(0);
Lease6 lease_client2 = client.getLease(1);
if (lease_client1.addr_.toText() != "3000::100") {
lease_client1 = client.getLease(1);
lease_client2 = client.getLease(0);
}
// The lifetimes should be set to 0, as an explicit notification to the
// client to stop using invalid prefix.
EXPECT_EQ(0, lease_client2.valid_lft_);
EXPECT_EQ(0, lease_client2.preferred_lft_);
EXPECT_EQ(0, lease_client1.valid_lft_);
EXPECT_EQ(0, lease_client1.preferred_lft_);
// Let's check the second lease
// The lifetimes should be set to 0, as an explicit notification to the
// client to stop using invalid prefix.
EXPECT_NE(0, lease_client2.valid_lft_);
EXPECT_NE(0, lease_client2.preferred_lft_);
// Check that server still has the same lease.
Lease6Ptr lease_server = checkLease(lease_client);
EXPECT_TRUE(lease_server);
......@@ -616,12 +640,24 @@ TEST_F(RebindTest, directClientPDChangingPrefix) {
" sent a response indicating that the client should stop using the"
" lease, by setting lifetime values to 0.";
// Get the client's lease.
ASSERT_EQ(1, client.getLeaseNum());
Lease6 lease_client2 = client.getLease(0);
ASSERT_EQ(2, client.getLeaseNum());
// Client should get two entries. One with the invalid address he requested
// with zeroed lifetimes and a second one with the actual prefix he has
// with non-zero lifetimes.
Lease6 lease_client1 = client.getLease(0);
Lease6 lease_client2 = client.getLease(1);
// The lifetimes should be set to 0, as an explicit notification to the
// client to stop using invalid prefix.
EXPECT_EQ(0, lease_client2.valid_lft_);
EXPECT_EQ(0, lease_client2.preferred_lft_);
EXPECT_EQ(0, lease_client1.valid_lft_);
EXPECT_EQ(0, lease_client1.preferred_lft_);
// The lifetimes should be set to 0, as an explicit notification to the
// client to stop using invalid prefix.
EXPECT_NE(0, lease_client2.valid_lft_);
EXPECT_NE(0, lease_client2.preferred_lft_);
// Check that server still has the same lease.
Lease6Ptr lease_server = checkLease(lease_client);
ASSERT_TRUE(lease_server);
......
......@@ -17,6 +17,7 @@
#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/host.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcp/dhcp6.h>
#include <hooks/server_hooks.h>
#include <hooks/hooks_manager.h>
......@@ -37,12 +38,16 @@ struct AllocEngineHooks {
int hook_index_lease4_select_; ///< index for "lease4_receive" hook point
int hook_index_lease4_renew_; ///< index for "lease4_renew" hook point
int hook_index_lease6_select_; ///< index for "lease6_receive" hook point
int hook_index_lease6_renew_; ///< index for "lease6_renew" hook point
int hook_index_lease6_rebind_; ///< index for "lease6_rebind" hook point
/// Constructor that registers hook points for AllocationEngine
AllocEngineHooks() {
hook_index_lease4_select_ = HooksManager::registerHook("lease4_select");
hook_index_lease4_renew_ = HooksManager::registerHook("lease4_renew");
hook_index_lease6_select_ = HooksManager::registerHook("lease6_select");
hook_index_lease6_renew_ = HooksManager::registerHook("lease6_renew");
hook_index_lease6_rebind_ = HooksManager::registerHook("lease6_rebind");
}
};
......@@ -381,9 +386,7 @@ AllocEngine::allocateLeases6(ClientContext6& ctx) {
if (!leases.empty()) {
// Return old leases so the server can see what has changed.
return (updateFqdnData(leases, ctx.fwd_dns_update_,
ctx.rev_dns_update_,
ctx.hostname_, ctx.fake_allocation_));
return (updateFqdnData(ctx, leases));
}
// If leases are empty at this stage, it means that we used to have
......@@ -485,7 +488,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
IOAddress hint("::");
if (!ctx.hints_.empty()) {
/// @todo: We support only one hint for now
hint = ctx.hints_[0];
hint = ctx.hints_[0].first;
}
// check if the hint is in pool and is available
......@@ -598,6 +601,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
if (ctx.type_ == Lease::TYPE_PD) {
Pool6Ptr pool = boost::dynamic_pointer_cast<Pool6>(
ctx.subnet_->getPool(ctx.type_, candidate, false));
/// @todo: verify that the pool is non-null
prefix_len = pool->getLength();
}
......@@ -666,17 +670,45 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, Lease6Collection& exis
IOAddress addr = resv->second.getPrefix();
uint8_t prefix_len = resv->second.getPrefixLen();
// Check if already have this lease on the existing_leases list.
for (Lease6Collection::const_iterator l = existing_leases.begin();
l != existing_leases.end(); ++l) {
// Ok, we already have a lease for this reservation and it's usable
if (((*l)->addr_ == addr) && (*l)->valid_lft_ != 0) {
return;
}
}
// If there's a lease for this address, let's not create it.
// It doesn't matter whether it is for this client or for someone else.
if (LeaseMgrFactory::instance().getLease6(ctx.type_, addr)) {
continue;
}
if (!LeaseMgrFactory::instance().getLease6(ctx.type_, addr)) {
// Ok, let's create a new lease...
Lease6Ptr lease = createLease6(ctx, addr, prefix_len);
// ... and add it to the existing leases list.
existing_leases.push_back(lease);
// Ok, let's create a new lease...
Lease6Ptr lease = createLease6(ctx, addr, prefix_len);
if (ctx.type_ == Lease::TYPE_NA) {
LOG_INFO(dhcpsrv_logger, DHCPSRV_HR_RESERVED_ADDR_GRANTED)
.arg(addr.toText()).arg(ctx.duid_->toText());
} else {
LOG_INFO(dhcpsrv_logger, DHCPSRV_HR_RESERVED_PREFIX_GRANTED)
.arg(addr.toText()).arg(static_cast<int>(prefix_len))
.arg(ctx.duid_->toText());
}
// ... and add it to the existing leases list.
existing_leases.push_back(lease);
// We found a lease for this client and this IA. Let's return.
// Returning after the first lease was assigned is useful if we
// have multiple reservations for the same client. If the client
// sends 2 IAs, the first time we call allocateReservedLeases6 will
// use the first reservation and return. The second time, we'll
// go over the first reservation, but will discover that there's
// a lease corresponding to it and will skip it and then pick
// the second reservation and turn it into the lease. This approach
// would work for any number of reservations.
return;
}
}
}
......@@ -710,11 +742,25 @@ AllocEngine::removeNonmatchingReservedLeases6(ClientContext6& ctx,
// Ok, we have a problem. This host has a lease that is reserved
// for someone else. We need to recover from this.
if (ctx.type_ == Lease::TYPE_NA) {
LOG_INFO(dhcpsrv_logger, DHCPSRV_HR_REVOKED_ADDR6_LEASE)
.arg((*candidate)->addr_.toText()).arg(ctx.duid_->toText())
.arg(host->getIdentifierAsText());
} else {
LOG_INFO(dhcpsrv_logger, DHCPSRV_HR_REVOKED_PREFIX6_LEASE)
.arg((*candidate)->addr_.toText())
.arg(static_cast<int>((*candidate)->prefixlen_))
.arg(ctx.duid_->toText())
.arg(host->getIdentifierAsText());
}
// Remove this lease from LeaseMgr
LeaseMgrFactory::instance().deleteLease((*candidate)->addr_);
/// @todo: Probably trigger a hook here
// In principle, we could trigger a hook here, but we will do this
// only if we get serious complaints from actual users. We want the
// conflict resolution procedure to really work and user libraries
// should not interfere with it.
// Add this to the list of removed leases.
ctx.old_leases_.push_back(*candidate);
......@@ -1603,22 +1649,19 @@ AllocEngine::updateLease4Information(const Lease4Ptr& lease,
}
Lease6Collection
AllocEngine::updateFqdnData(const Lease6Collection& leases,
const bool fwd_dns_update,
const bool rev_dns_update,
const std::string& hostname,
const bool fake_allocation) {
AllocEngine::updateFqdnData(ClientContext6& ctx, const Lease6Collection& leases) {
Lease6Collection updated_leases;
for (Lease6Collection::const_iterator lease_it = leases.begin();
lease_it != leases.end(); ++lease_it) {
Lease6Ptr lease(new Lease6(**lease_it));
lease->fqdn_fwd_ = fwd_dns_update;
lease->fqdn_rev_ = rev_dns_update;
lease->hostname_ = hostname;
if (!fake_allocation &&
lease->fqdn_fwd_ = ctx.fwd_dns_update_;
lease->fqdn_rev_ = ctx.rev_dns_update_;
lease->hostname_ = ctx.hostname_;
if (!ctx.fake_allocation_ &&
((lease->fqdn_fwd_ != (*lease_it)->fqdn_fwd_) ||
(lease->fqdn_rev_ != (*lease_it)->fqdn_rev_) ||
(lease->hostname_ != (*lease_it)->hostname_))) {
ctx.changed_leases_.push_back(*lease_it);
LeaseMgrFactory::instance().updateLease6(lease);
}
updated_leases.push_back(lease);
......@@ -1636,6 +1679,158 @@ AllocEngine::AllocatorPtr AllocEngine::getAllocator(Lease::Type type) {
return (alloc->second);
}
Lease6Collection
AllocEngine::renewLeases6(ClientContext6& ctx) {
try {
if (!ctx.subnet_) {
isc_throw(InvalidOperation, "Subnet is required for allocation");
}
if (!ctx.duid_) {
isc_throw(InvalidOperation, "DUID is mandatory for allocation");
}
// Check which host reservation mode is supported in this subnet.
Subnet::HRMode hr_mode = ctx.subnet_->getHostReservationMode();
// Check if there's a host reservation for this client. Attempt to get
// host info only if reservations are not disabled.