int hook_index_buffer6_receive_;///< index for "buffer6_receive" hook point
int hook_index_pkt6_receive_; ///< index for "pkt6_receive" hook point
int hook_index_subnet6_select_; ///< index for "subnet6_select" hook point
- int hook_index_lease6_renew_; ///< index for "lease6_renew" hook point
- int hook_index_lease6_rebind_; ///< index for "lease6_rebind" hook point
int hook_index_lease6_release_; ///< index for "lease6_release" hook point
int hook_index_pkt6_send_; ///< index for "pkt6_send" hook point
int hook_index_buffer6_send_; ///< index for "buffer6_send" hook point
hook_index_buffer6_receive_= HooksManager::registerHook("buffer6_receive");
hook_index_pkt6_receive_ = HooksManager::registerHook("pkt6_receive");
hook_index_subnet6_select_ = HooksManager::registerHook("subnet6_select");
- hook_index_lease6_renew_ = HooksManager::registerHook("lease6_renew");
- hook_index_lease6_rebind_ = HooksManager::registerHook("lease6_rebind");
hook_index_lease6_release_ = HooksManager::registerHook("lease6_release");
hook_index_pkt6_send_ = HooksManager::registerHook("pkt6_send");
hook_index_buffer6_send_ = HooksManager::registerHook("buffer6_send");
return (ia_rsp);
}
- Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- *duid, ia->getIAID(),
- subnet->getID());
-
- // Client extending a lease that we don't know about.
- if (!lease) {
- // Insert status code NoBinding to indicate that the lease does not
- // exist for this client.
- ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
- "Sorry, no known leases for this duid/iaid/subnet."));
+ // Set up T1, T2 timers
+ ia_rsp->setT1(subnet->getT1());
+ ia_rsp->setT2(subnet->getT2());
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_EXTEND_NA_UNKNOWN)
- .arg(duid->toText())
- .arg(ia->getIAID())
- .arg(subnet->toText());
+ // At this point, we have to make make some decisions with respect to
+ // the FQDN option that we have generated as a result of receiving
+ // client's FQDN. In particular, we have to get to know if the DNS
+ // update will be performed or not. It is possible that option is NULL,
+ // which is valid condition if client didn't request DNS updates and
+ // server didn't force the update.
+ bool do_fwd = false;
+ bool do_rev = false;
+ Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<
+ Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
+ if (fqdn) {
+ CfgMgr::instance().getD2ClientMgr().getUpdateDirections(*fqdn, do_fwd, do_rev);
+ }
- return (ia_rsp);
+ std::string hostname;
+ if (fqdn && (do_fwd || do_rev)) {
+ hostname = fqdn->getDomainName();
}
- // Keep the old data in case the callout tells us to skip update.
- Lease6 old_data = *lease;
+ // Create client context for this renewal
+ static const IOAddress none("::");
+ AllocEngine::ClientContext6 ctx(subnet, duid, ia->getIAID(),
+ none, Lease::TYPE_NA, do_fwd, do_rev,
+ hostname, false);
- bool invalid_addr = false;
- // Check what address the client has sent. The address should match the one
- // that we have associated with the IAID. If it doesn't match we have two
- // options: allocate the address for the client, if the server's
- // configuration allows to do so, or notify the client that his address is
- // wrong. For now we will just notify the client that the address is wrong,
- // but both solutions require that we check the contents of the IA_NA option
- // sent by the client. Without this check we would extend the existing lease
- // even if the address being carried in the IA_NA is different than the
- // one we are extending.
- Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<
- Option6IAAddr>(ia->getOption(D6O_IAADDR));
- if (iaaddr && (iaaddr->getAddress() != lease->addr_)) {
- Option6IAAddrPtr zero_lft_addr(new Option6IAAddr(D6O_IAADDR,
- iaaddr->getAddress(),
- 0, 0));
- ia_rsp->addOption(zero_lft_addr);
- // Mark that the client's notion of the address is invalid, so as
- // we don't update the actual client's lease.
- invalid_addr = true;
+ ctx.callout_handle_ = getCalloutHandle(query);
+ ctx.query_ = query;
+ ctx.ia_rsp_ = ia_rsp;
- } else {
+ // Attempt to get MAC address using configured mechanisms.
+ // It's ok if there response is NULL. Hardware address is optional in Lease6.
+ ctx.hwaddr_ = getMAC(query);
- // At this point, we have to make make some decisions with respect to
- // the FQDN option that we have generated as a result of receiving
- // client's FQDN. In particular, we have to get to know if the DNS
- // update will be performed or not. It is possible that option is NULL,
- // which is valid condition if client didn't request DNS updates and
- // server didn't force the update.
- bool do_fwd = false;
- bool do_rev = false;
- Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<
- Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
- if (fqdn) {
- CfgMgr::instance().getD2ClientMgr().getUpdateDirections(*fqdn,
- do_fwd,
- do_rev);
+ // Extract addresses that are being renewed.
+ int hints_count = 0;
+ OptionCollection addrs = ia->getOptions();
+ for (OptionCollection::const_iterator it = addrs.begin();
+ it != addrs.end(); ++it) {
+ if (it->second->getType() != D6O_IAADDR) {
+ continue;
}
-
- std::string hostname;
- if (do_fwd || do_rev) {
- hostname = fqdn->getDomainName();
+ Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<Option6IAAddr>(it->second);
+ if (!iaaddr) {
+ // That's weird.
+ continue;
}
+ ctx.hints_.push_back(iaaddr->getAddress());
+
+ // We need to remember it as we'll be removing hints from this list as
+ // we extend, cancel or otherwise deal with the leases.
+ hints_count++;
+ }
+
+ Lease6Collection leases = alloc_engine_->renewLeases6(ctx);
+
+ // Ok, now we have the leases extended. We have:
+ // - what the client tried to renew in ctx.hints_
+ // - what we actually assigned in leases
+ // - old leases that are no longer valid in ctx.old_leases_
+
+ // For all leases we have now, add the IAADDR with non-zero lifetimes.
+ for (Lease6Collection::const_iterator l = leases.begin(); l != leases.end(); ++l) {
+ Option6IAAddrPtr iaaddr(new Option6IAAddr(D6O_IAADDR,
+ (*l)->addr_, (*l)->preferred_lft_, (*l)->valid_lft_));
+ ia_rsp->addOption(iaaddr);
+
+ // Now remove this address from the hints list.
+ ctx.hints_.erase(std::remove(ctx.hints_.begin(), ctx.hints_.end(),
+ (*l)->addr_), ctx.hints_.end());
+ }
+
+ // For the leases that we just retired, send the addresses with 0 lifetimes.
+ for (Lease6Collection::const_iterator l = ctx.old_leases_.begin();
+ l != ctx.old_leases_.end(); ++l) {
+ Option6IAAddrPtr iaaddr(new Option6IAAddr(D6O_IAADDR,
+ (*l)->addr_, 0, 0));
+ ia_rsp->addOption(iaaddr);
+
+ // Now remove this address from the hints list.
+ ctx.hints_.erase(std::remove(ctx.hints_.begin(), ctx.hints_.end(),
+ (*l)->addr_), ctx.hints_.end());
// If the new FQDN settings have changed for the lease, we need to
// delete any existing FQDN records for this lease.
- if ((lease->hostname_ != hostname) || (lease->fqdn_fwd_ != do_fwd) ||
- (lease->fqdn_rev_ != do_rev)) {
+ if (((*l)->hostname_ != hostname) || ((*l)->fqdn_fwd_ != do_fwd) ||
+ ((*l)->fqdn_rev_ != do_rev)) {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
DHCP6_DDNS_LEASE_RENEW_FQDN_CHANGE)
- .arg(lease->toText())
+ .arg((*l)->toText())
.arg(hostname)
.arg(do_rev ? "true" : "false")
.arg(do_fwd ? "true" : "false");
- createRemovalNameChangeRequest(lease);
+ createRemovalNameChangeRequest(*l);
}
-
- lease->preferred_lft_ = subnet->getPreferred();
- lease->valid_lft_ = subnet->getValid();
- lease->t1_ = subnet->getT1();
- lease->t2_ = subnet->getT2();
- lease->cltt_ = time(NULL);
- lease->hostname_ = hostname;
- lease->fqdn_fwd_ = do_fwd;
- lease->fqdn_rev_ = do_rev;
-
- /// @todo: check if hardware address has changed since last update.
- /// And modify lease->hwaddr_ if it did.
-
- ia_rsp->setT1(subnet->getT1());
- ia_rsp->setT2(subnet->getT2());
-
- Option6IAAddrPtr addr(new Option6IAAddr(D6O_IAADDR, lease->addr_,
- lease->preferred_lft_,
- lease->valid_lft_));
- ia_rsp->addOption(addr);
}
- bool skip = false;
- // Get the callouts specific for the processed message and execute them.
- int hook_point = query->getType() == DHCPV6_RENEW ?
- Hooks.hook_index_lease6_renew_ : Hooks.hook_index_lease6_rebind_;
- if (HooksManager::calloutsPresent(hook_point)) {
- CalloutHandlePtr callout_handle = getCalloutHandle(query);
-
- // Delete all previous arguments
- callout_handle->deleteAllArguments();
-
- // Pass the original packet
- callout_handle->setArgument("query6", query);
-
- // Pass the lease to be updated
- callout_handle->setArgument("lease6", lease);
-
- // Pass the IA option to be sent in response
- callout_handle->setArgument("ia_na", ia_rsp);
-
- // Call all installed callouts
- HooksManager::callCallouts(hook_point, *callout_handle);
-
- // Callouts decided to skip the next processing step. The next
- // processing step would to actually renew the lease, so skip at this
- // stage means "keep the old lease as it is".
- if (callout_handle->getSkip()) {
- skip = true;
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS,
- DHCP6_HOOK_LEASE6_EXTEND_SKIP)
- .arg(query->getName());
- }
+ // Finally, if there are any addresses requested that we haven't dealt with
+ // already, inform the client that he can't have them.
+ for (vector<IOAddress>::const_iterator addr = ctx.hints_.begin();
+ addr != ctx.hints_.end(); ++addr) {
+ Option6IAAddrPtr iaaddr(new Option6IAAddr(D6O_IAADDR,
+ *addr, 0, 0));
+ ia_rsp->addOption(iaaddr);
}
- if (!skip) {
- // If the client has sent an invalid address, it shouldn't affect the
- // lease in our lease database.
- if (!invalid_addr) {
- LeaseMgrFactory::instance().updateLease6(lease);
+ // All is left is to insert the status code.
+ if (leases.empty()) {
+ // We did not assign anything. If client has sent something, then
+ // the status code is NoBinding, if he sent an empty IA_NA, then it's
+ // NoAddrsAvailable
+ if (hints_count) {
+ // Insert status code NoBinding to indicate that the lease does not
+ // exist for this client.
+ ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
+ "Sorry, no known leases for this duid/iaid/subnet."));
+
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_EXTEND_NA_UNKNOWN)
+ .arg(duid->toText())
+ .arg(ia->getIAID())
+ .arg(subnet->toText());
+ } else {
+ ia_rsp->addOption(createStatusCode(STATUS_NoAddrsAvail,
+ "Sorry, no addresses could be assigned at this time."));
}
} else {
- // Copy back the original date to the lease. For MySQL it doesn't make
- // much sense, but for memfile, the Lease6Ptr points to the actual lease
- // in memfile, so the actual update is performed when we manipulate
- // fields of returned Lease6Ptr, the actual updateLease6() is no-op.
- *lease = old_data;
+ // Yay, the client still has something. For now, let's not insert
+ // status-code=success to conserve bandwidth.
}
return (ia_rsp);
}
-
+ (void)invalid_prefix;
+#if 0
bool skip = false;
// Execute all callouts registered for packet6_send
// Get the callouts specific for the processed message and execute them.
// fields of returned Lease6Ptr, the actual updateLease6() is no-op.
*lease = old_data;
}
+#endif
return (ia_rsp);
}
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
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
// 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);
// 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.
// 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);
// 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, subnet_->getT1(), subnet_->getT2());
checkMsgStatusCode(reply, STATUS_Success);
// There should be no address returned in RELEASE (see RFC3315, 18.2.6)
// 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, subnet_->getT1(), subnet_->getT2());
checkMsgStatusCode(reply, STATUS_NoBinding);
// Check that the lease is not there
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);
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
// 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)
+ uint16_t expected_status_code, uint32_t expected_t1,
+ uint32_t expected_t2)
{
// 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());
+ // 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>
// 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
#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>
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");
}
};
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.
+ if (hr_mode != Subnet::HR_DISABLED) {
+
+ ctx.host_ = HostMgr::instance().get6(ctx.subnet_->getID(), ctx.duid_,
+ ctx.hwaddr_);
+ }
+
+ // Check if there are any leases for this client.
+ Lease6Collection leases = LeaseMgrFactory::instance()
+ .getLeases6(ctx.type_, *ctx.duid_, ctx.iaid_, ctx.subnet_->getID());
+
+ // Now we have 3 lists:
+ // 1. what client requested (ctx.hints_)
+ // 2. what leases we currently have (leases)
+ // 3. reservation list: ctx.hosts_->getIPv6Reservations(TYPE_NA)
+
+ // The behavior here is similar to how we process requests, but
+ // there are noticable differences.
+
+ // Now do the checks:
+ // Case 1. if there are no leases, and there are reservations...
+ // 1.1. are the reserved addresses are used by someone else?
+ // yes: we have a problem
+ // no: assign them => done
+ // Case 2. if there are leases and there are no reservations...
+ // 2.1 are the leases reserved for someone else?
+ // yes: release them, assign something else
+ // no: renew them => done
+ // Case 3. if there are leases and there are reservations...
+ // 3.1 are the leases matching reservations?
+ // yes: renew them => done
+ // no: release existing leases, assign new ones based on reservations
+ // Case 4/catch-all. if there are no leases and no reservations...
+ // assign new leases
+ //
+
+ // Extend all existing leases.
+ for (Lease6Collection::iterator l = leases.begin(); l != leases.end(); ++l) {
+ extendLease6(ctx, *l);
+ }
+
+ return (leases);
+
+ } catch (const isc::Exception& e) {
+
+ // Some other error, return an empty lease.
+ LOG_ERROR(dhcpsrv_logger, DHCPSRV_ADDRESS6_ALLOC_ERROR).arg(e.what());
+ }
+
+ return (Lease6Collection());
+}
+
+void
+AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) {
+
+ if (!lease || !ctx.subnet_) {
+ return;
+ }
+
+ // Keep the old data in case the callout tells us to skip update.
+ Lease6 old_data = *lease;
+
+ lease->preferred_lft_ = ctx.subnet_->getPreferred();
+ lease->valid_lft_ = ctx.subnet_->getValid();
+ lease->t1_ = ctx.subnet_->getT1();
+ lease->t2_ = ctx.subnet_->getT2();
+ lease->cltt_ = time(NULL);
+ lease->hostname_ = ctx.hostname_;
+ lease->fqdn_fwd_ = ctx.fwd_dns_update_;
+ lease->fqdn_rev_ = ctx.rev_dns_update_;
+ lease->hwaddr_ = ctx.hwaddr_;
+
+ bool skip = false;
+ // Get the callouts specific for the processed message and execute them.
+ int hook_point = ctx.query_->getType() == DHCPV6_RENEW ?
+ Hooks.hook_index_lease6_renew_ : Hooks.hook_index_lease6_rebind_;
+ if (HooksManager::calloutsPresent(hook_point)) {
+ CalloutHandlePtr callout_handle = ctx.callout_handle_;
+
+ // Delete all previous arguments
+ callout_handle->deleteAllArguments();
+
+ // Pass the original packet
+ callout_handle->setArgument("query6", ctx.query_);
+
+ // Pass the lease to be updated
+ callout_handle->setArgument("lease6", lease);
+
+ /// @todo: get the IA_NA/IA_PD
+ // Pass the IA option to be sent in response
+ callout_handle->setArgument("ia_na", ctx.ia_rsp_);
+
+ // Call all installed callouts
+ HooksManager::callCallouts(hook_point, *callout_handle);
+
+ // Callouts decided to skip the next processing step. The next
+ // processing step would to actually renew the lease, so skip at this
+ // stage means "keep the old lease as it is".
+ if (callout_handle->getSkip()) {
+ skip = true;
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_HOOKS,
+ DHCPSRV_HOOK_LEASE6_EXTEND_SKIP)
+ .arg(ctx.query_->getName());
+ }
+ }
+
+ if (!skip) {
+ LeaseMgrFactory::instance().updateLease6(lease);
+ } else {
+ // Copy back the original date to the lease. For MySQL it doesn't make
+ // much sense, but for memfile, the Lease6Ptr points to the actual lease
+ // in memfile, so the actual update is performed when we manipulate
+ // fields of returned Lease6Ptr, the actual updateLease6() is no-op.
+ *lease = old_data;
+ }
+}
+
AllocEngine::~AllocEngine() {
// no need to delete allocator. smart_ptr will do the trick for us
}
#include <asiolink/io_address.h>
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
+#include <dhcp/pkt6.h>
+#include <dhcp/option6_ia.h>
#include <dhcpsrv/host.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/lease_mgr.h>
/// May be NULL if there are no reservations.
ConstHostPtr host_;
+ /// @brief A pointer to the client's message
+ ///
+ /// This is used exclusively for hook purposes.
+ Pkt6Ptr query_;
+
+ /// @brief A pointer to the IA_NA/IA_PD option to be sent in response
+ Option6IAPtr ia_rsp_;
+
/// @brief Default constructor.
ClientContext6()
: subnet_(), duid_(), iaid_(0), type_(Lease::TYPE_NA), hwaddr_(),
const Lease::Type type, const bool fwd_dns, const bool
rev_dns, const std::string& hostname, const bool
fake_allocation):
- subnet_(subnet), duid_(duid), iaid_(iaid), type_(type), hwaddr_(),
- hints_(), fwd_dns_update_(fwd_dns), rev_dns_update_(rev_dns),
- hostname_(hostname), fake_allocation_(fake_allocation),
- old_leases_(), host_() {
- hints_.push_back(hint);
+ subnet_(subnet), duid_(duid), iaid_(iaid), type_(type), hwaddr_(),
+ hints()_, fwd_dns_update_(fwd_dns), rev_dns_update_(rev_dns),
+ hostname_(hostname), fake_allocation_(fake_allocation), old_leases_(),
+ host_() {
+
+ static asiolink::IOAddress any("::");
+
+ if (hint != any) {
+ hints_.push_back(hint);
+ }
// callout_handle, host pointers initiated to NULL by their
// respective constructors.
}
Lease6Collection
allocateLeases6(ClientContext6& ctx);
+
+ /// @brief Renews existing DHCPv6 leases for a given IA.
+ ///
+ /// This method updates the leases associated with a specified IA container.
+ /// It will extend the leases under normal circumstances, but sometimes
+ /// there may be reasons why not to do so. Such a reasons may be:
+ /// - client attempts to renew an address that is not valid
+ /// - client attempts to renew an address that is now reserved for someone
+ /// else (see host reservation)
+ /// - client's leases does not match his reservations
+ ///
+ /// This method will call the lease4_renew callout.
+ ///
+ /// @param ctx Message processing context. It holds various information
+ /// extracted from the client's message and required to allocate a lease.
+ /// In particular, @ref ClientContext6::hints_ provides list of addresses or
+ /// prefixes the client had sent. @ref ClientContext6::old_leases_ will
+ /// contain removed leases in this case.
+ ///
+ /// @return Returns renewed lease.
+ Lease6Collection
+ renewLeases6(ClientContext6& ctx);
+
+
+
/// @brief returns allocator for a given pool type
/// @param type type of pool (V4, IA, TA or PD)
/// @throw BadValue if allocator for a given type is missing
removeLeases(Lease6Collection& container,
const asiolink::IOAddress& addr);
+ /// @brief Extends specified IPv6 lease
+ ///
+ /// This method attempts to extend the lease. It will call the lease6_renew
+ /// or lease6_rebind hooks (depending on the client's message specified in
+ /// ctx.query). The lease will be extended in LeaseMgr, unless the hooks
+ /// library will set skip flag.
+ ///
+ /// @param ctx client context that passes all necessary information. See
+ /// @ref ClientContext6 for details.
+ /// @param lease IPv6 lease to be extended.
+ void extendLease6(ClientContext6& ctx, Lease6Ptr lease);
+
/// @brief a pointer to currently used allocator
///
/// For IPv4, there will be only one allocator: TYPE_V4
no lease4 should be assigned. The server will not put that lease in its
database and the client will get a NAK packet.
+% DHCPSRV_HOOK_LEASE6_EXTEND_SKIP DHCPv6 lease lifetime was not extended because a callout set the skip flag for message %1
+or lease6_rebind hook point set the skip flag. For this particular hook
+point, the setting of the flag by a callout instructs the server to not
+extend the lifetime for a lease. If client requested renewal of multiples
+leases (by sending multiple IA options), the server will skip the renewal
+of the one in question and will proceed with other renewals as usual.
+
% DHCPSRV_HOOK_LEASE6_SELECT_SKIP Lease6 (non-temporary) creation was skipped, because of callout skip flag.
This debug message is printed when a callout installed on lease6_select
hook point sets the skip flag. It means that the server was told that
/// transition from single to multi address per IA. It may also be used
/// in other cases where at most one lease is expected in the database.
///
- /// It is a wrapper around getLease6(), which returns a collection of
+ /// It is a wrapper around getLeases6(), which returns a collection of
/// leases. That collection can be converted into a single pointer if
/// there are no leases (NULL pointer) or one lease (use that single lease).
/// If there are more leases in the collection, the function will