From 1d77f223f523a9434f46c70490d99db4be5cb15f Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Fri, 3 Jun 2016 15:20:02 +0200 Subject: [PATCH] [4320] ClientContext6 now holds information about multiple IAs. --- src/bin/dhcp6/dhcp6_srv.cc | 155 +++++++++-------- src/bin/dhcp6/dhcp6_srv.h | 25 +-- src/bin/dhcp6/tests/dhcp6_test_utils.h | 2 +- src/lib/dhcpsrv/alloc_engine.cc | 136 ++++++++------- src/lib/dhcpsrv/alloc_engine.h | 159 +++++++++++------- .../dhcpsrv/tests/alloc_engine6_unittest.cc | 123 ++++++++------ .../tests/alloc_engine_expiration_unittest.cc | 11 +- .../tests/alloc_engine_hooks_unittest.cc | 23 +-- src/lib/dhcpsrv/tests/alloc_engine_utils.cc | 64 ++++--- 9 files changed, 393 insertions(+), 305 deletions(-) diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index e5dad328b4..1ebb7cbfcc 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -276,12 +276,16 @@ Dhcpv6Srv::testUnicast(const Pkt6Ptr& pkt) const { return (true); } -AllocEngine::ClientContext6 -Dhcpv6Srv::createContext(const Pkt6Ptr& pkt) { - AllocEngine::ClientContext6 ctx; +void +Dhcpv6Srv::initContext(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx) { ctx.subnet_ = selectSubnet(pkt); + ctx.duid_ = pkt->getClientId(), + ctx.fwd_dns_update_ = false; + ctx.rev_dns_update_ = false; + ctx.fake_allocation_ = false; + ctx.hostname_ = ""; ctx.query_ = pkt; - ctx.duid_ = pkt->getClientId(); + ctx.callout_handle_ = getCalloutHandle(pkt); ctx.hwaddr_ = getMAC(pkt); // Collect host identifiers if host reservations enabled. The identifiers @@ -314,8 +318,6 @@ Dhcpv6Srv::createContext(const Pkt6Ptr& pkt) { // Find host reservations using specified identifiers. alloc_engine_->findReservation(ctx); } - - return (ctx); } bool Dhcpv6Srv::run() { @@ -1283,7 +1285,7 @@ Dhcpv6Srv::getMAC(const Pkt6Ptr& pkt) { OptionPtr Dhcpv6Srv::assignIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, - AllocEngine::ClientContext6& orig_ctx, + AllocEngine::ClientContext6& ctx, boost::shared_ptr ia) { // Check if the client sent us a hint in his IA_NA. Clients may send an @@ -1302,8 +1304,7 @@ Dhcpv6Srv::assignIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, .arg(hint_opt ? hint.toText() : "(no hint)"); // convenience values - const Subnet6Ptr& subnet = orig_ctx.subnet_; - const DuidPtr& duid = orig_ctx.duid_; + const Subnet6Ptr& subnet = ctx.subnet_; // If there is no subnet selected for handling this IA_NA, the only thing left to do is // to say that we are sorry, but the user won't get an address. As a convenience, we @@ -1351,14 +1352,13 @@ Dhcpv6Srv::assignIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, // will try to honor the hint, but it is just a hint - some other address // may be used instead. If fake_allocation is set to false, the lease will // be inserted into the LeaseMgr as well. - AllocEngine::ClientContext6 ctx(subnet, duid, ia->getIAID(), - hint, Lease::TYPE_NA, do_fwd, do_rev, - orig_ctx.hostname_, fake_allocation); - ctx.callout_handle_ = getCalloutHandle(query); - ctx.hwaddr_ = orig_ctx.hwaddr_; - ctx.host_ = orig_ctx.host_; - ctx.query_ = orig_ctx.query_; - ctx.host_identifiers_ = orig_ctx.host_identifiers_; + ctx.createIAContext(); + ctx.fwd_dns_update_ = do_fwd; + ctx.rev_dns_update_ = do_rev; + ctx.fake_allocation_ = fake_allocation; + ctx.currentIA().iaid_ = ia->getIAID(); + ctx.currentIA().addHint(hint); + ctx.currentIA().type_ = Lease::TYPE_NA; Lease6Collection leases = alloc_engine_->allocateLeases6(ctx); @@ -1417,7 +1417,7 @@ Dhcpv6Srv::assignIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, OptionPtr Dhcpv6Srv::assignIA_PD(const Pkt6Ptr& query, const Pkt6Ptr& answer, - AllocEngine::ClientContext6& orig_ctx, + AllocEngine::ClientContext6& ctx, boost::shared_ptr ia) { // Check if the client sent us a hint in his IA_PD. Clients may send an @@ -1437,8 +1437,7 @@ Dhcpv6Srv::assignIA_PD(const Pkt6Ptr& query, const Pkt6Ptr& answer, .arg(hint_opt ? hint.toText() : "(no hint)"); - const Subnet6Ptr& subnet = orig_ctx.subnet_; - const DuidPtr& duid = orig_ctx.duid_; + const Subnet6Ptr& subnet = ctx.subnet_; // Create IA_PD that we will put in the response. // Do not use OptionDefinition to create option's instance so @@ -1474,13 +1473,13 @@ Dhcpv6Srv::assignIA_PD(const Pkt6Ptr& query, const Pkt6Ptr& answer, // will try to honor the hint, but it is just a hint - some other address // may be used instead. If fake_allocation is set to false, the lease will // be inserted into the LeaseMgr as well. - AllocEngine::ClientContext6 ctx(subnet, duid, ia->getIAID(), hint, Lease::TYPE_PD, - false, false, string(), fake_allocation); - ctx.callout_handle_ = getCalloutHandle(query); - ctx.hwaddr_ = orig_ctx.hwaddr_; - ctx.host_ = orig_ctx.host_; - ctx.query_ = orig_ctx.query_; - ctx.host_identifiers_ = orig_ctx.host_identifiers_; + + ctx.createIAContext(); + ctx.fake_allocation_ = fake_allocation; + ctx.currentIA().iaid_ = ia->getIAID(); + ctx.currentIA().addHint(hint); + ctx.currentIA().type_ = Lease::TYPE_PD; + Lease6Collection leases = alloc_engine_->allocateLeases6(ctx); @@ -1532,7 +1531,7 @@ Dhcpv6Srv::assignIA_PD(const Pkt6Ptr& query, const Pkt6Ptr& answer, OptionPtr Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, - AllocEngine::ClientContext6& orig_ctx, + AllocEngine::ClientContext6& ctx, boost::shared_ptr ia) { LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_NA_EXTEND) @@ -1540,8 +1539,7 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, .arg(ia->getIAID()); // convenience values - const Subnet6Ptr& subnet = orig_ctx.subnet_; - const DuidPtr& duid = orig_ctx.duid_; + const Subnet6Ptr& subnet = ctx.subnet_; // Create empty IA_NA option with IAID matching the request. Option6IAPtr ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID())); @@ -1575,16 +1573,12 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, do_fwd, do_rev); } - // Create client context for this renewal - AllocEngine::ClientContext6 ctx(subnet, duid, ia->getIAID(), - IOAddress::IPV6_ZERO_ADDRESS(), Lease::TYPE_NA, - do_fwd, do_rev, orig_ctx.hostname_, false); - - ctx.callout_handle_ = getCalloutHandle(query); - ctx.query_ = query; - ctx.ia_rsp_ = ia_rsp; - ctx.hwaddr_ = orig_ctx.hwaddr_; - ctx.host_ = orig_ctx.host_; + ctx.createIAContext(); + ctx.fwd_dns_update_ = do_fwd; + ctx.rev_dns_update_ = do_rev; + ctx.currentIA().iaid_ = ia->getIAID(); + ctx.currentIA().type_ = Lease::TYPE_NA; + ctx.currentIA().ia_rsp_ = ia_rsp; // Extract the addresses that the client is trying to obtain. OptionCollection addrs = ia->getOptions(); @@ -1603,7 +1597,7 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, // this. continue; } - ctx.hints_.push_back(make_pair(iaaddr->getAddress(), 128)); + ctx.currentIA().addHint(iaaddr->getAddress()); } Lease6Collection leases = alloc_engine_->renewLeases6(ctx); @@ -1613,6 +1607,8 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, // - what we actually assigned in leases // - old leases that are no longer valid in ctx.old_leases_ + AllocEngine::HintContainer hints = ctx.currentIA().hints_; + // 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, @@ -1624,22 +1620,21 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, .arg(ia_rsp->getIAID()); // Now remove this address from the hints list. - AllocEngine::HintType tmp((*l)->addr_, 128); - ctx.hints_.erase(std::remove(ctx.hints_.begin(), ctx.hints_.end(), tmp), - ctx.hints_.end()); + AllocEngine::HintType hint_type((*l)->addr_, 128); + hints.erase(std::remove(hints.begin(), hints.end(), hint_type), + 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) { + for (Lease6Collection::const_iterator l = ctx.currentIA().old_leases_.begin(); + l != ctx.currentIA().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. - AllocEngine::HintType tmp((*l)->addr_, 128); - ctx.hints_.erase(std::remove(ctx.hints_.begin(), ctx.hints_.end(), tmp), - ctx.hints_.end()); + AllocEngine::HintType hint_type((*l)->addr_, 128); + hints.erase(std::remove(hints.begin(), hints.end(), hint_type), hints.end()); // If the new FQDN settings have changed for the lease, we need to // delete any existing FQDN records for this lease. @@ -1659,8 +1654,8 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, // Finally, if there are any addresses requested that we haven't dealt with // already, inform the client that he can't have them. - for (AllocEngine::HintContainer::const_iterator hint = ctx.hints_.begin(); - hint != ctx.hints_.end(); ++hint) { + for (AllocEngine::HintContainer::const_iterator hint = hints.begin(); + hint != hints.end(); ++hint) { Option6IAAddrPtr iaaddr(new Option6IAAddr(D6O_IAADDR, hint->first, 0, 0)); ia_rsp->addOption(iaaddr); @@ -1682,15 +1677,15 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, OptionPtr Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query, - AllocEngine::ClientContext6& orig_ctx, + AllocEngine::ClientContext6& ctx, boost::shared_ptr ia) { LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_PD_EXTEND) .arg(query->getLabel()) .arg(ia->getIAID()); - const Subnet6Ptr& subnet = orig_ctx.subnet_; - const DuidPtr& duid = orig_ctx.duid_; + const Subnet6Ptr& subnet = ctx.subnet_; + const DuidPtr& duid = ctx.duid_; // Let's create a IA_PD response and fill it in later Option6IAPtr ia_rsp(new Option6IA(D6O_IA_PD, ia->getIAID())); @@ -1729,16 +1724,10 @@ Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query, ia_rsp->setT1(subnet->getT1()); ia_rsp->setT2(subnet->getT2()); - // Create client context for this renewal - static const IOAddress none("::"); - AllocEngine::ClientContext6 ctx(subnet, duid, ia->getIAID(), none, - Lease::TYPE_PD, false, false, string(""), - false); - ctx.callout_handle_ = getCalloutHandle(query); - ctx.query_ = query; - ctx.ia_rsp_ = ia_rsp; - ctx.hwaddr_ = orig_ctx.hwaddr_; - ctx.host_ = orig_ctx.host_; + ctx.createIAContext(); + ctx.currentIA().iaid_ = ia->getIAID(); + ctx.currentIA().type_ = Lease::TYPE_PD; + ctx.currentIA().ia_rsp_ = ia_rsp; // Extract prefixes that the client is trying to renew. OptionCollection addrs = ia->getOptions(); @@ -1759,7 +1748,7 @@ Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query, } // Put the client's prefix into the hints list. - ctx.hints_.push_back(make_pair(prf->getAddress(), prf->getLength())); + ctx.currentIA().addHint(prf->getAddress(), prf->getLength()); } // Call Allocation Engine and attempt to renew leases. Number of things @@ -1772,6 +1761,8 @@ Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query, // in PD context) Lease6Collection leases = alloc_engine_->renewLeases6(ctx); + AllocEngine::HintContainer hints = ctx.currentIA().hints_; + // For all the leases we have now, add the IAPPREFIX with non-zero lifetimes for (Lease6Collection::const_iterator l = leases.begin(); l != leases.end(); ++l) { Option6IAPrefixPtr prf(new Option6IAPrefix(D6O_IAPREFIX, @@ -1785,9 +1776,9 @@ Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query, .arg(ia->getIAID()); // Now remove this address from the hints list. - AllocEngine::HintType tmp((*l)->addr_, (*l)->prefixlen_); - ctx.hints_.erase(std::remove(ctx.hints_.begin(), ctx.hints_.end(), tmp), - ctx.hints_.end()); + AllocEngine::HintType hint_type((*l)->addr_, (*l)->prefixlen_); + hints.erase(std::remove(hints.begin(), hints.end(), hint_type), + hints.end()); } /// @todo: Maybe we should iterate over ctx.old_leases_, i.e. the leases @@ -1797,8 +1788,8 @@ Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query, // zero lifetimes // Finally, if there are any addresses requested that we haven't dealt with // already, inform the client that he can't have them. - for (AllocEngine::HintContainer::const_iterator prefix = ctx.hints_.begin(); - prefix != ctx.hints_.end(); ++prefix) { + for (AllocEngine::HintContainer::const_iterator prefix = hints.begin(); + prefix != hints.end(); ++prefix) { // Send the prefix with the zero lifetimes only if the prefix // contains non-zero value. A zero value indicates that the hint was // for the prefix length. @@ -2238,7 +2229,8 @@ Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) { sanityCheck(solicit, MANDATORY, FORBIDDEN); // Let's create a simplified client context here. - AllocEngine::ClientContext6 ctx = createContext(solicit); + AllocEngine::ClientContext6 ctx; + initContext(solicit, ctx); Pkt6Ptr response(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid())); @@ -2282,7 +2274,8 @@ Dhcpv6Srv::processRequest(const Pkt6Ptr& request) { sanityCheck(request, MANDATORY, MANDATORY); // Let's create a simplified client context here. - AllocEngine::ClientContext6 ctx = createContext(request); + AllocEngine::ClientContext6 ctx; + initContext(request, ctx); Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, request->getTransid())); @@ -2307,7 +2300,8 @@ Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) { sanityCheck(renew, MANDATORY, MANDATORY); // Let's create a simplified client context here. - AllocEngine::ClientContext6 ctx = createContext(renew); + AllocEngine::ClientContext6 ctx; + initContext(renew, ctx); Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, renew->getTransid())); @@ -2331,7 +2325,8 @@ Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) { sanityCheck(rebind, MANDATORY, FORBIDDEN); // Let's create a simplified client context here. - AllocEngine::ClientContext6 ctx = createContext(rebind); + AllocEngine::ClientContext6 ctx; + initContext(rebind, ctx); Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, rebind->getTransid())); @@ -2355,7 +2350,8 @@ Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) { sanityCheck(confirm, MANDATORY, FORBIDDEN); // Let's create a simplified client context here. - AllocEngine::ClientContext6 ctx = createContext(confirm); + AllocEngine::ClientContext6 ctx; + initContext(confirm, ctx); // Get IA_NAs from the Confirm. If there are none, the message is // invalid and must be discarded. There is nothing more to do. @@ -2445,7 +2441,8 @@ Dhcpv6Srv::processRelease(const Pkt6Ptr& release) { sanityCheck(release, MANDATORY, MANDATORY); // Let's create a simplified client context here. - AllocEngine::ClientContext6 ctx = createContext(release); + AllocEngine::ClientContext6 ctx; + initContext(release, ctx); Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, release->getTransid())); @@ -2472,7 +2469,8 @@ Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) { Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid())); // Let's create a simplified client context here. - AllocEngine::ClientContext6 ctx = createContext(decline); + AllocEngine::ClientContext6 ctx; + initContext(decline, ctx); // Copy client options (client-id, also relay information if present) copyClientOptions(decline, reply); @@ -2748,7 +2746,8 @@ Dhcpv6Srv::processInfRequest(const Pkt6Ptr& inf_request) { sanityCheck(inf_request, OPTIONAL, OPTIONAL); // Let's create a simplified client context here. - AllocEngine::ClientContext6 ctx = createContext(inf_request); + AllocEngine::ClientContext6 ctx; + initContext(inf_request, ctx); // Create a Reply packet, with the same trans-id as the client's. Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, inf_request->getTransid())); diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h index 0f35e5e5d7..6e157df4ed 100644 --- a/src/bin/dhcp6/dhcp6_srv.h +++ b/src/bin/dhcp6/dhcp6_srv.h @@ -307,13 +307,13 @@ protected: /// @param answer server's response to the client's message. This /// message should contain Client FQDN option being sent by the server /// to the client (if the client sent this option to the server). - /// @param orig_ctx client context (contains subnet, duid and other parameters) + /// @param ctx client context (contains subnet, duid and other parameters) /// @param ia pointer to client's IA_NA option (client's request) /// /// @return IA_NA option (server's response) OptionPtr assignIA_NA(const isc::dhcp::Pkt6Ptr& query, const isc::dhcp::Pkt6Ptr& answer, - AllocEngine::ClientContext6& orig_ctx, + AllocEngine::ClientContext6& ctx, Option6IAPtr ia); /// @brief Processes IA_PD option (and assigns prefixes if necessary). @@ -326,12 +326,12 @@ protected: /// /// @param query client's message (typically SOLICIT or REQUEST) /// @param answer server's response to the client's message. - /// @param orig_ctx client context (contains subnet, duid and other parameters) + /// @param ctx client context (contains subnet, duid and other parameters) /// @param ia pointer to client's IA_PD option (client's request) /// @return IA_PD option (server's response) OptionPtr assignIA_PD(const Pkt6Ptr& query, const isc::dhcp::Pkt6Ptr& answer, - AllocEngine::ClientContext6& orig_ctx, + AllocEngine::ClientContext6& ctx, boost::shared_ptr ia); /// @brief Extends lifetime of the specific IA_NA option. @@ -357,12 +357,12 @@ protected: /// @param answer server's response to the client's message. This /// message should contain Client FQDN option being sent by the server /// to the client (if the client sent this option to the server). - /// @param orig_ctx client context (contains subnet, duid and other parameters) + /// @param ctx client context (contains subnet, duid and other parameters) /// @param ia IA_NA option which carries address for which lease lifetime /// will be extended. /// @return IA_NA option (server's response) OptionPtr extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer, - AllocEngine::ClientContext6& orig_ctx, + AllocEngine::ClientContext6& ctx, Option6IAPtr ia); /// @brief Extends lifetime of the prefix. @@ -377,14 +377,14 @@ protected: /// (see RFC3633, section 12.2. for details). /// /// @param query client's message - /// @param orig_ctx client context (contains subnet, duid and other parameters) + /// @param ctx client context (contains subnet, duid and other parameters) /// @param ia IA_PD option that is being renewed /// @return IA_PD option (server's response) /// @throw DHCPv6DiscardMessageError when the message being processed should /// be discarded by the server, i.e. there is no binding for the client doing /// Rebind. OptionPtr extendIA_PD(const Pkt6Ptr& query, - AllocEngine::ClientContext6& orig_ctx, + AllocEngine::ClientContext6& ctx, Option6IAPtr ia); /// @brief Releases specific IA_NA option @@ -656,9 +656,9 @@ protected: /// - there is no such option provided by the server) void processRSOO(const Pkt6Ptr& query, const Pkt6Ptr& rsp); - /// @brief Creates client context for specified packet + /// @brief Initializes client context for specified packet /// - /// Instantiates the ClientContext6 and then: + /// This method: /// - Performs the subnet selection and stores the result in context /// - Extracts the duid from the packet and saves it to the context /// - Extracts the hardware address from the packet and saves it to @@ -666,8 +666,9 @@ protected: /// - Performs host reservation lookup and stores the result in the /// context /// - /// @return client context - AllocEngine::ClientContext6 createContext(const Pkt6Ptr& pkt); + /// @param pkt pointer to a packet for which context will be created. + /// @param [out] ctx reference to context object to be initialized. + void initContext(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx); /// @brief this is a prefix added to the contend of vendor-class option /// diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.h b/src/bin/dhcp6/tests/dhcp6_test_utils.h index 37ae7d200c..4a373ebfaa 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.h +++ b/src/bin/dhcp6/tests/dhcp6_test_utils.h @@ -131,7 +131,7 @@ public: using Dhcpv6Srv::shutdown_; using Dhcpv6Srv::name_change_reqs_; using Dhcpv6Srv::VENDOR_CLASS_PREFIX; - using Dhcpv6Srv::createContext; + using Dhcpv6Srv::initContext; /// @brief packets we pretend to receive /// diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index edbefccd45..84961fd692 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -35,6 +35,7 @@ #include #include #include +#include using namespace isc::asiolink; using namespace isc::dhcp; @@ -331,31 +332,24 @@ AllocEngine::findReservationInternal(ContextType& ctx, // ########################################################################## AllocEngine::ClientContext6::ClientContext6() - : subnet_(), duid_(), iaid_(0), type_(Lease::TYPE_NA), hwaddr_(), - hints_(), fwd_dns_update_(false), rev_dns_update_(false), hostname_(""), - callout_handle_(), fake_allocation_(false), old_leases_(), host_(), - query_(), ia_rsp_(), host_identifiers_() { + : query_(), fake_allocation_(false), subnet_(), duid_(), + hwaddr_(), host_identifiers_(), host_(), fwd_dns_update_(false), + rev_dns_update_(false), hostname_(), callout_handle_(), + ias_() { } -AllocEngine::ClientContext6::ClientContext6(const Subnet6Ptr& subnet, const DuidPtr& duid, - const uint32_t iaid, - const isc::asiolink::IOAddress& hint, - const Lease::Type type, const bool fwd_dns, +AllocEngine::ClientContext6::ClientContext6(const Subnet6Ptr& subnet, + const DuidPtr& duid, + 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_(), query_(), ia_rsp_(), host_identifiers_() { - - static asiolink::IOAddress any("::"); - - if (hint != any) { - hints_.push_back(std::make_pair(hint, 128)); - } - // callout_handle, host pointers initiated to NULL by their - // respective constructors. + const bool fake_allocation, + const Pkt6Ptr& query, + const CalloutHandlePtr& callout_handle) + : query_(query), fake_allocation_(fake_allocation), subnet_(subnet), + duid_(duid), hwaddr_(), host_identifiers_(), host_(), + fwd_dns_update_(fwd_dns), rev_dns_update_(rev_dns), + hostname_(hostname), callout_handle_(callout_handle), ias_() { // Initialize host identifiers. if (duid) { @@ -363,6 +357,17 @@ AllocEngine::ClientContext6::ClientContext6(const Subnet6Ptr& subnet, const Duid } } +AllocEngine::ClientContext6::IAContext::IAContext() + : iaid_(0), type_(Lease::TYPE_NA), hints_(), old_leases_(), + changed_leases_(), ia_rsp_() { +} + +void +AllocEngine::ClientContext6:: +IAContext::addHint(const asiolink::IOAddress& prefix, + const uint8_t prefix_len) { + hints_.push_back(std::make_pair(prefix, prefix_len)); +} void AllocEngine::findReservation(ClientContext6& ctx) { findReservationInternal(ctx, boost::bind(&HostMgr::get6, @@ -384,7 +389,9 @@ AllocEngine::allocateLeases6(ClientContext6& ctx) { // Check if there are existing leases for that subnet/duid/iaid // combination. Lease6Collection leases = - LeaseMgrFactory::instance().getLeases6(ctx.type_, *ctx.duid_, ctx.iaid_, + LeaseMgrFactory::instance().getLeases6(ctx.currentIA().type_, + *ctx.duid_, + ctx.currentIA().iaid_, ctx.subnet_->getID()); // Now do the checks: @@ -544,11 +551,11 @@ AllocEngine::allocateLeases6(ClientContext6& ctx) { Lease6Collection AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { - AllocatorPtr allocator = getAllocator(ctx.type_); + AllocatorPtr allocator = getAllocator(ctx.currentIA().type_); if (!allocator) { isc_throw(InvalidOperation, "No allocator specified for " - << Lease6::typeToText(ctx.type_)); + << Lease6::typeToText(ctx.currentIA().type_)); } // Check which host reservation mode is supported in this subnet. @@ -557,19 +564,20 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { Lease6Collection leases; IOAddress hint = IOAddress::IPV6_ZERO_ADDRESS(); - if (!ctx.hints_.empty()) { + if (!ctx.currentIA().hints_.empty()) { /// @todo: We support only one hint for now - hint = ctx.hints_[0].first; + hint = ctx.currentIA().hints_[0].first; } // check if the hint is in pool and is available // This is equivalent of subnet->inPool(hint), but returns the pool Pool6Ptr pool = boost::dynamic_pointer_cast< - Pool6>(ctx.subnet_->getPool(ctx.type_, hint, false)); + Pool6>(ctx.subnet_->getPool(ctx.currentIA().type_, hint, false)); if (pool) { /// @todo: We support only one hint for now - Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(ctx.type_, hint); + Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, + hint); if (!lease) { // In-pool reservations: Check if this address is reserved for someone @@ -623,7 +631,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // Copy an existing, expired lease so as it can be returned // to the caller. Lease6Ptr old_lease(new Lease6(*lease)); - ctx.old_leases_.push_back(old_lease); + ctx.currentIA().old_leases_.push_back(old_lease); /// We found a lease and it is expired, so we can reuse it lease = reuseExpiredLease(lease, ctx, pool->getLength()); @@ -649,7 +657,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // - we find an address for which the lease has expired // - we exhaust number of tries uint64_t max_attempts = (attempts_ > 0 ? attempts_ : - ctx.subnet_->getPoolCapacity(ctx.type_)); + ctx.subnet_->getPoolCapacity(ctx.currentIA().type_)); for (uint64_t i = 0; i < max_attempts; ++i) { IOAddress candidate = allocator->pickAddress(ctx.subnet_, ctx.duid_, hint); @@ -667,14 +675,14 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // The first step is to find out prefix length. It is 128 for // non-PD leases. uint8_t prefix_len = 128; - if (ctx.type_ == Lease::TYPE_PD) { + if (ctx.currentIA().type_ == Lease::TYPE_PD) { Pool6Ptr pool = boost::dynamic_pointer_cast( - ctx.subnet_->getPool(ctx.type_, candidate, false)); + ctx.subnet_->getPool(ctx.currentIA().type_, candidate, false)); /// @todo: verify that the pool is non-null prefix_len = pool->getLength(); } - Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(ctx.type_, + Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, candidate); if (!existing) { @@ -685,7 +693,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { if (lease) { // We are allocating a new lease (not renewing). So, the // old lease should be NULL. - ctx.old_leases_.clear(); + ctx.currentIA().old_leases_.clear(); leases.push_back(lease); return (leases); @@ -699,7 +707,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // Copy an existing, expired lease so as it can be returned // to the caller. Lease6Ptr old_lease(new Lease6(*existing)); - ctx.old_leases_.push_back(old_lease); + ctx.currentIA().old_leases_.push_back(old_lease); existing = reuseExpiredLease(existing, ctx, @@ -723,7 +731,8 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { } void -AllocEngine::allocateReservedLeases6(ClientContext6& ctx, Lease6Collection& existing_leases) { +AllocEngine::allocateReservedLeases6(ClientContext6& ctx, + Lease6Collection& existing_leases) { // If there are no reservations or the reservation is v4, there's nothing to do. if (!ctx.host_ || !ctx.host_->hasIPv6Reservation()) { @@ -734,7 +743,8 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, Lease6Collection& exis } // Let's convert this from Lease::Type to IPv6Reserv::Type - IPv6Resrv::Type type = ctx.type_ == Lease::TYPE_NA ? IPv6Resrv::TYPE_NA : IPv6Resrv::TYPE_PD; + IPv6Resrv::Type type = ctx.currentIA().type_ == Lease::TYPE_NA ? + IPv6Resrv::TYPE_NA : IPv6Resrv::TYPE_PD; // Get the IPv6 reservations of specified type. const IPv6ResrvRange& reservs = ctx.host_->getIPv6Reservations(type); @@ -767,14 +777,15 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, Lease6Collection& exis // 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)) { + if (!LeaseMgrFactory::instance().getLease6(ctx.currentIA().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); - if (ctx.type_ == Lease::TYPE_NA) { + if (ctx.currentIA().type_ == Lease::TYPE_NA) { LOG_INFO(alloc_engine_logger, ALLOC_ENGINE_V6_HR_ADDR_GRANTED) .arg(addr.toText()) .arg(ctx.query_->getLabel()); @@ -829,7 +840,7 @@ 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) { + if (ctx.currentIA().type_ == Lease::TYPE_NA) { LOG_INFO(alloc_engine_logger, ALLOC_ENGINE_V6_REVOKED_ADDR_LEASE) .arg((*candidate)->addr_.toText()).arg(ctx.duid_->toText()) .arg(host->getIdentifierAsText()); @@ -850,8 +861,8 @@ AllocEngine::removeNonmatchingReservedLeases6(ClientContext6& ctx, // Need to decrease statistic for assigned addresses. StatsMgr::instance().addValue( StatsMgr::generateName("subnet", ctx.subnet_->getID(), - ctx.type_ == Lease::TYPE_NA ? "assigned-nas" : - "assigned-pds"), + ctx.currentIA().type_ == Lease::TYPE_NA ? + "assigned-nas" : "assigned-pds"), static_cast(-1)); // In principle, we could trigger a hook here, but we will do this @@ -860,7 +871,7 @@ AllocEngine::removeNonmatchingReservedLeases6(ClientContext6& ctx, // should not interfere with it. // Add this to the list of removed leases. - ctx.old_leases_.push_back(*candidate); + ctx.currentIA().old_leases_.push_back(*candidate); // Let's remove this candidate from existing leases removeLeases(existing_leases, (*candidate)->addr_); @@ -902,7 +913,8 @@ AllocEngine::removeNonreservedLeases6(ClientContext6& ctx, // leases for deletion, by setting appropriate pointers to NULL. for (Lease6Collection::iterator lease = existing_leases.begin(); lease != existing_leases.end(); ++lease) { - IPv6Resrv resv(ctx.type_ == Lease::TYPE_NA ? IPv6Resrv::TYPE_NA : IPv6Resrv::TYPE_PD, + IPv6Resrv resv(ctx.currentIA().type_ == Lease::TYPE_NA ? + IPv6Resrv::TYPE_NA : IPv6Resrv::TYPE_PD, (*lease)->addr_, (*lease)->prefixlen_); if (!ctx.host_->hasReservation(resv)) { // We have reservations, but not for this lease. Release it. @@ -916,14 +928,14 @@ AllocEngine::removeNonreservedLeases6(ClientContext6& ctx, // Need to decrease statistic for assigned addresses. StatsMgr::instance().addValue( StatsMgr::generateName("subnet", ctx.subnet_->getID(), - ctx.type_ == Lease::TYPE_NA ? "assigned-nas" : - "assigned-pds"), + ctx.currentIA().type_ == Lease::TYPE_NA ? + "assigned-nas" : "assigned-pds"), static_cast(-1)); /// @todo: Probably trigger a hook here // Add this to the list of removed leases. - ctx.old_leases_.push_back(*lease); + ctx.currentIA().old_leases_.push_back(*lease); // Set this pointer to NULL. The pointer is still valid. We're just // setting the Lease6Ptr to NULL value. We'll remove all NULL @@ -964,7 +976,7 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx, } // address, lease type and prefixlen (0) stay the same - expired->iaid_ = ctx.iaid_; + expired->iaid_ = ctx.currentIA().iaid_; expired->duid_ = ctx.duid_; expired->preferred_lft_ = ctx.subnet_->getPreferred(); expired->valid_lft_ = ctx.subnet_->getValid(); @@ -1039,14 +1051,15 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx, const IOAddress& addr, uint8_t prefix_len) { - if (ctx.type_ != Lease::TYPE_PD) { + if (ctx.currentIA().type_ != Lease::TYPE_PD) { prefix_len = 128; // non-PD lease types must be always /128 } - Lease6Ptr lease(new Lease6(ctx.type_, addr, ctx.duid_, ctx.iaid_, - ctx.subnet_->getPreferred(), ctx.subnet_->getValid(), - ctx.subnet_->getT1(), ctx.subnet_->getT2(), - ctx.subnet_->getID(), ctx.hwaddr_, prefix_len)); + Lease6Ptr lease(new Lease6(ctx.currentIA().type_, addr, ctx.duid_, + ctx.currentIA().iaid_, ctx.subnet_->getPreferred(), + ctx.subnet_->getValid(), ctx.subnet_->getT1(), + ctx.subnet_->getT2(), ctx.subnet_->getID(), + ctx.hwaddr_, prefix_len)); lease->fqdn_fwd_ = ctx.fwd_dns_update_; lease->fqdn_rev_ = ctx.rev_dns_update_; @@ -1094,11 +1107,11 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx, if (status) { // The lease insertion succeeded - if the lease is in the // current subnet lets bump up the statistic. - if (ctx.subnet_->inPool(ctx.type_, addr)) { + if (ctx.subnet_->inPool(ctx.currentIA().type_, addr)) { StatsMgr::instance().addValue( StatsMgr::generateName("subnet", ctx.subnet_->getID(), - ctx.type_ == Lease::TYPE_NA ? "assigned-nas" : - "assigned-pds"), + ctx.currentIA().type_ == Lease::TYPE_NA ? + "assigned-nas" : "assigned-pds"), static_cast(1)); } @@ -1138,7 +1151,8 @@ AllocEngine::renewLeases6(ClientContext6& ctx) { // Check if there are any leases for this client. Lease6Collection leases = LeaseMgrFactory::instance() - .getLeases6(ctx.type_, *ctx.duid_, ctx.iaid_, ctx.subnet_->getID()); + .getLeases6(ctx.currentIA().type_, *ctx.duid_, + ctx.currentIA().iaid_, ctx.subnet_->getID()); if (!leases.empty()) { LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, @@ -1226,7 +1240,7 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) { static_cast(-1)); // Add it to the removed leases list. - ctx.old_leases_.push_back(lease); + ctx.currentIA().old_leases_.push_back(lease); return; } @@ -1275,9 +1289,9 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) { // Pass the IA option to be sent in response if (lease->type_ == Lease::TYPE_NA) { - callout_handle->setArgument("ia_na", ctx.ia_rsp_); + callout_handle->setArgument("ia_na", ctx.currentIA().ia_rsp_); } else { - callout_handle->setArgument("ia_pd", ctx.ia_rsp_); + callout_handle->setArgument("ia_pd", ctx.currentIA().ia_rsp_); } // Call all installed callouts @@ -1334,7 +1348,7 @@ AllocEngine::updateLeaseData(ClientContext6& ctx, const Lease6Collection& leases (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); + ctx.currentIA().changed_leases_.push_back(*lease_it); LeaseMgrFactory::instance().updateLease6(lease); } updated_leases.push_back(lease); diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h index f7d9d225fc..fb450359a4 100644 --- a/src/lib/dhcpsrv/alloc_engine.h +++ b/src/lib/dhcpsrv/alloc_engine.h @@ -281,27 +281,40 @@ public: /// that the big advantage of using the context structure to pass /// information to the allocation engine methods is that adding /// new information doesn't modify the API of the allocation engine. - struct ClientContext6 { + struct ClientContext6 : public boost::noncopyable { + + /// @name Parameters pertaining to DHCPv6 message + //@{ + + /// @brief A pointer to the client's message + /// + /// This is used exclusively for hook purposes. + Pkt6Ptr query_; + + /// @brief Indicates if this is a real or fake allocation. + /// + /// The real allocation is when the allocation engine is supposed + /// to make an update in a lease database: create new lease, or + /// update existing lease. + bool fake_allocation_; + /// @brief Subnet selected for the client by the server. Subnet6Ptr subnet_; /// @brief Client identifier DuidPtr duid_; - /// @brief iaid IAID field from IA_NA or IA_PD that is being processed - uint32_t iaid_; - - /// @brief Lease type (IA or PD) - Lease::Type type_; - /// @brief Hardware/MAC address (if available, may be NULL) HWAddrPtr hwaddr_; - /// @brief client's hints + /// @brief A list holding host identifiers extracted from a message + /// received by the server. + IdentifierList host_identifiers_; + + /// @brief A pointer to the object identifying host reservations. /// - /// There will typically be just one address, but the protocol allows - /// more than one address or prefix for each IA container. - HintContainer hints_; + /// May be NULL if there are no reservations. + ConstHostPtr host_; /// @brief A boolean value which indicates that server takes /// responsibility for the forward DNS Update for this lease @@ -322,45 +335,60 @@ public: /// @brief Callout handle associated with the client's message. hooks::CalloutHandlePtr callout_handle_; - /// @brief Indicates if this is a real or fake allocation. - /// - /// The real allocation is when the allocation engine is supposed - /// to make an update in a lease database: create new lease, or - /// update existing lease. - bool fake_allocation_; - - /// @brief A pointer to any old leases that the client had before update - /// but are no longer valid after the update/allocation. - /// - /// This collection is typically empty, except cases when we are doing - /// address reassignment, e.g. because there is a host reservation that - /// gives this address to someone else, so we had to return the address, - /// and give a new one to this client. - Lease6Collection old_leases_; - - /// @brief A pointer to any leases that have changed FQDN information. - /// - /// This list may contain old versions of the leases that are still - /// valid. In particular, it will contain a lease if the client's - /// FQDN has changed. - Lease6Collection changed_leases_; - - /// @brief A pointer to the object identifying host reservations. - /// - /// 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 A list holding host identifiers extracted from a message - /// received by the server. - IdentifierList host_identifiers_; + //@} + + /// @brief Parameters pertaining to individual IAs. + struct IAContext { + + /// @brief iaid IAID field from IA_NA or IA_PD that is being + /// processed + uint32_t iaid_; + + /// @brief Lease type (IA or PD) + Lease::Type type_; + + /// @brief client's hints + /// + /// There will typically be just one address, but the protocol + /// allows more than one address or prefix for each IA container. + HintContainer hints_; + + /// @brief A pointer to any old leases that the client had before + /// update but are no longer valid after the update/allocation. + /// + /// This collection is typically empty, except cases when we are + /// doing address reassignment, e.g. because there is a host + /// reservation that gives this address to someone else, so we had + /// to return the address, and give a new one to this client. + Lease6Collection old_leases_; + + /// @brief A pointer to any leases that have changed FQDN + /// information. + /// + /// This list may contain old versions of the leases that are still + /// valid. In particular, it will contain a lease if the client's + /// FQDN has changed. + Lease6Collection changed_leases_; + + /// @brief A pointer to the IA_NA/IA_PD option to be sent in + /// response + Option6IAPtr ia_rsp_; + + /// @brief Default constructor. + /// + /// Initializes @ref type_ to @c Lease::TYPE_NA and @ref iaid_ to 0. + IAContext(); + + /// @brief Convenience method adding new hint. + /// + /// @param prefix Prefix or address. + /// @param prefix_len Prefix length. Default is 128 for addresses. + void addHint(const asiolink::IOAddress& prefix, + const uint8_t prefix_len = 128); + + }; + + std::vector ias_; /// @brief Conveniece function adding host identifier into /// @ref host_identifiers_ list. @@ -372,6 +400,17 @@ public: host_identifiers_.push_back(IdentifierPair(id_type, identifier)); } + IAContext& currentIA() { + if (ias_.empty()) { + createIAContext(); + } + return (ias_.back()); + } + + void createIAContext() { + ias_.push_back(IAContext()); + }; + /// @brief Default constructor. ClientContext6(); @@ -383,9 +422,6 @@ public: /// /// @param subnet subnet the allocation should come from /// @param duid Client's DUID - /// @param iaid iaid field from the IA_NA container that client sent - /// @param hint a hint that the client provided - /// @param type lease type (IA, TA or PD) /// @param fwd_dns A boolean value which indicates that server takes /// responsibility for the forward DNS Update for this lease /// (if true). @@ -393,13 +429,18 @@ public: /// responsibility for the reverse DNS Update for this lease /// (if true). /// @param hostname A fully qualified domain-name of the client. - /// @param fake_allocation is this real i.e. REQUEST (false) or just picking - /// an address for SOLICIT that is not really allocated (true) + /// @param fake_allocation is this real i.e. REQUEST (false) or just + /// picking an address for SOLICIT that is not really allocated + /// (true) + /// @param query Pointer to the DHCPv6 message being processed. + /// @param callout_handle Callout handle associated with a client's + /// message ClientContext6(const Subnet6Ptr& subnet, const DuidPtr& duid, - const uint32_t iaid, const isc::asiolink::IOAddress& hint, - const Lease::Type type, const bool fwd_dns, const bool - rev_dns, const std::string& hostname, const bool - fake_allocation); + const bool fwd_dns, const bool rev_dns, + const std::string& hostname, const bool fake_allocation, + const Pkt6Ptr& query, + const hooks::CalloutHandlePtr& callout_handle = + hooks::CalloutHandlePtr()); }; /// @brief Allocates IPv6 leases for a given IA container diff --git a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc index 1b2808d186..4db57d7a39 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc @@ -147,16 +147,17 @@ TEST_F(AllocEngine6Test, allocateAddress6Nulls) { // Allocations without subnet are not allowed Lease6Ptr lease; - AllocEngine::ClientContext6 ctx1(Subnet6Ptr(), duid_, iaid_, IOAddress("::"), - Lease::TYPE_NA, false, false, "", false); - ctx1.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx1(Subnet6Ptr(), duid_, false, false, "", false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234))); + ctx1.currentIA().iaid_ = iaid_; + EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx1))); ASSERT_FALSE(lease); // Allocations without DUID are not allowed either - AllocEngine::ClientContext6 ctx2(subnet_, DuidPtr(), iaid_, IOAddress("::"), - Lease::TYPE_NA, false, false, "", false); - ctx2.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx2(subnet_, DuidPtr(), false, false, "", false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234))); + ctx2.currentIA().iaid_ = iaid_; EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx2))); ASSERT_FALSE(lease); } @@ -403,10 +404,10 @@ TEST_F(AllocEngine6Test, smallPool6) { initFqdn("myhost.example.com", true, true); Lease6Ptr lease; - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"), - Lease::TYPE_NA, fqdn_fwd_, fqdn_rev_, - hostname_, false); - ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, duid_, fqdn_fwd_, fqdn_rev_, + hostname_, false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234))); + ctx.currentIA().iaid_ = iaid_; EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); // Check that we got that single lease @@ -427,7 +428,7 @@ TEST_F(AllocEngine6Test, smallPool6) { // This is a new lease allocation. The old lease corresponding to a newly // allocated lease should be NULL. - ASSERT_TRUE(ctx.old_leases_.empty()); + ASSERT_TRUE(ctx.currentIA().old_leases_.empty()); } // This test checks if all addresses in a pool are currently used, the attempt @@ -458,11 +459,12 @@ TEST_F(AllocEngine6Test, outOfAddresses6) { // There is just a single address in the pool and allocated it to someone // else, so the allocation should fail - Lease6Ptr lease2; - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"), - Lease::TYPE_NA, false, false, "", false); - ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, + query); + ctx.currentIA().iaid_ = iaid_; + Lease6Ptr lease2; EXPECT_NO_THROW(lease2 = expectOneLease(engine->allocateLeases6(ctx))); EXPECT_FALSE(lease2); @@ -497,9 +499,9 @@ TEST_F(AllocEngine6Test, solicitReuseExpiredLease6) { ASSERT_TRUE(lease->expired()); // CASE 1: Asking for any address - AllocEngine::ClientContext6 ctx1(subnet_, duid_, iaid_, IOAddress("::"), - Lease::TYPE_NA, fqdn_fwd_, fqdn_rev_, hostname_, true); - ctx1.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx1(subnet_, duid_, fqdn_fwd_, fqdn_rev_, hostname_, + true, Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234))); + ctx1.currentIA().iaid_ = iaid_; EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx1))); // Check that we got that single lease @@ -510,9 +512,11 @@ TEST_F(AllocEngine6Test, solicitReuseExpiredLease6) { checkLease6(lease, Lease::TYPE_NA, 128); // CASE 2: Asking specifically for this address - AllocEngine::ClientContext6 ctx2(subnet_, duid_, iaid_, addr, Lease::TYPE_NA, - false, false, "", true); - ctx2.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx2(subnet_, duid_, false, false, "", true, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234))); + ctx2.currentIA().iaid_ = iaid_; + ctx2.currentIA().addHint(addr); + EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx2))); // Check that we got that single lease @@ -556,9 +560,11 @@ TEST_F(AllocEngine6Test, requestReuseExpiredLease6) { StatsMgr::instance().setValue(name, static_cast(100)); // A client comes along, asking specifically for this address - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, addr, Lease::TYPE_NA, - false, false, "", false); - ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234))); + ctx.currentIA().iaid_ = iaid_; + ctx.currentIA().addHint(addr); + EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); // Check that he got that single lease @@ -570,7 +576,7 @@ TEST_F(AllocEngine6Test, requestReuseExpiredLease6) { EXPECT_FALSE(lease->fqdn_rev_); // Check that the old lease has been returned. - Lease6Ptr old_lease = expectOneLease(ctx.old_leases_); + Lease6Ptr old_lease = expectOneLease(ctx.currentIA().old_leases_); // It should at least have the same IPv6 address. EXPECT_EQ(lease->addr_, old_lease->addr_); // Check that it carries not updated FQDN data. @@ -1170,9 +1176,11 @@ TEST_F(AllocEngine6Test, reservedAddress) { int success = 0; int failure = 0; for (int i = 0; i < 30; i++) { - AllocEngine::ClientContext6 ctx(subnet_, clients[i], iaid_, IOAddress("::"), - Lease::TYPE_NA, false, false, "", false); - ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, clients[i], false, false, "", + false, query); + ctx.currentIA().iaid_ = iaid_; + findReservation(engine, ctx); Lease6Collection leases = engine.allocateLeases6(ctx); if (leases.empty()) { @@ -1194,9 +1202,9 @@ TEST_F(AllocEngine6Test, reservedAddress) { // We're now pretty sure that any clients other than the reserved address // will not get any service. Now let's check if the client that has the // address reserved, will get it (despite the pool being depleted). - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"), - Lease::TYPE_NA, false, false, "", false); - ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234))); + ctx.currentIA().iaid_ = iaid_; findReservation(engine, ctx); Lease6Collection leases = engine.allocateLeases6(ctx); @@ -1209,9 +1217,10 @@ TEST_F(AllocEngine6Test, allocateLeasesInvalidData) { AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100, true); // That looks like a valid context. - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"), - Lease::TYPE_NA, false, false, "", false); - ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234))); + ctx.currentIA().iaid_ = iaid_; + Lease6Collection leases; // Let's break it! @@ -1304,9 +1313,11 @@ TEST_F(AllocEngine6Test, DISABLED_reserved2AddressesSolicit) { AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100); - AllocEngine::ClientContext6 ctx1(subnet_, duid_, iaid_, IOAddress("::"), - pool_->getType(), false, false, "", true); - ctx1.query_.reset(new Pkt6(DHCPV6_SOLICIT, 1234)); + AllocEngine::ClientContext6 ctx1(subnet_, duid_, false, false, "", true, + Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234))); + ctx1.currentIA().iaid_ = iaid_; + ctx1.currentIA().type_ = pool_->getType(); + Lease6Collection leases1; findReservation(engine, ctx1); EXPECT_NO_THROW(leases1 = engine.allocateLeases6(ctx1)); @@ -1315,9 +1326,11 @@ TEST_F(AllocEngine6Test, DISABLED_reserved2AddressesSolicit) { // Double check that repeating the same duid/type/iaid will end up with // the same address. - AllocEngine::ClientContext6 ctx2(subnet_, duid_, iaid_, IOAddress("::"), - pool_->getType(), false, false, "", true); - ctx2.query_.reset(new Pkt6(DHCPV6_SOLICIT, 1234)); + AllocEngine::ClientContext6 ctx2(subnet_, duid_, false, false, "", true, + Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234))); + ctx2.currentIA().iaid_ = iaid_; + ctx2.currentIA().type_ = pool_->getType(); + Lease6Collection leases2; findReservation(engine, ctx2); EXPECT_NO_THROW(leases2 = engine.allocateLeases6(ctx2)); @@ -1326,9 +1339,11 @@ TEST_F(AllocEngine6Test, DISABLED_reserved2AddressesSolicit) { // Ok, now the tricky part. Request allocation for the same duid and type, but // different iaid. The second address should be assigned. - AllocEngine::ClientContext6 ctx3(subnet_, duid_, iaid_ + 1, IOAddress("::"), - pool_->getType(), false, false, "", true); - ctx3.query_.reset(new Pkt6(DHCPV6_SOLICIT, 1234)); + AllocEngine::ClientContext6 ctx3(subnet_, duid_, false, false, "", true, + Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234))); + ctx3.currentIA().iaid_ = iaid_ + 1; + ctx3.currentIA().type_ = pool_->getType(); + Lease6Collection leases3; findReservation(engine, ctx3); EXPECT_NO_THROW(leases3 = engine.allocateLeases6(ctx3)); @@ -1351,9 +1366,11 @@ TEST_F(AllocEngine6Test, reserved2Addresses) { AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100); - AllocEngine::ClientContext6 ctx1(subnet_, duid_, iaid_, IOAddress("::"), - pool_->getType(), false, false, "", false); - ctx1.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx1(subnet_, duid_, false, false, "", false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234))); + ctx1.currentIA().iaid_ = iaid_; + ctx1.currentIA().type_ = pool_->getType(); + Lease6Collection leases1; findReservation(engine, ctx1); EXPECT_NO_THROW(leases1 = engine.allocateLeases6(ctx1)); @@ -1362,9 +1379,10 @@ TEST_F(AllocEngine6Test, reserved2Addresses) { // Double check that repeating the same duid/type/iaid will end up with // the same address. - AllocEngine::ClientContext6 ctx2(subnet_, duid_, iaid_, IOAddress("::"), - pool_->getType(), false, false, "", false); - ctx2.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx2(subnet_, duid_, false, false, "", false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234))); + ctx2.currentIA().iaid_ = iaid_; + ctx2.currentIA().type_ = pool_->getType(); Lease6Collection leases2; findReservation(engine, ctx2); @@ -1374,9 +1392,10 @@ TEST_F(AllocEngine6Test, reserved2Addresses) { // Ok, now the tricky part. Request allocation for the same duid and type, but // different iaid. The second address should be assigned. - AllocEngine::ClientContext6 ctx3(subnet_, duid_, iaid_ + 1, IOAddress("::"), - pool_->getType(), false, false, "", false); - ctx3.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx3(subnet_, duid_, false, false, "", false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234))); + ctx3.currentIA().iaid_ = iaid_ + 1; + ctx3.currentIA().type_ = pool_->getType(); Lease6Collection leases3; findReservation(engine, ctx3); diff --git a/src/lib/dhcpsrv/tests/alloc_engine_expiration_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine_expiration_unittest.cc index 0fadc7fb51..ad23d1e3cf 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine_expiration_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine_expiration_unittest.cc @@ -1415,14 +1415,13 @@ ExpirationAllocEngine6Test::testReclaimReusedLeases(const uint16_t msg_type, for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) { // Build the context. - AllocEngine::ClientContext6 ctx(subnet, leases_[i]->duid_, 1, - leases_[i]->addr_, - Lease::TYPE_NA, + AllocEngine::ClientContext6 ctx(subnet, leases_[i]->duid_, false, false, leases_[i]->hostname_, - msg_type == DHCPV6_SOLICIT); - // Query is needed for logging purposes. - ctx.query_.reset(new Pkt6(msg_type, 0x1234)); + msg_type == DHCPV6_SOLICIT, + Pkt6Ptr(new Pkt6(msg_type, 0x1234))); + ctx.currentIA().iaid_ = 1; + ctx.currentIA().hints_.push_back(std::make_pair(leases_[i]->addr_, 128)); // Depending on the message type, we will call a different function. if (msg_type == DHCPV6_RENEW) { diff --git a/src/lib/dhcpsrv/tests/alloc_engine_hooks_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine_hooks_unittest.cc index d38439a418..ba7c7e665d 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine_hooks_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine_hooks_unittest.cc @@ -148,13 +148,12 @@ TEST_F(HookAllocEngine6Test, lease6_select) { EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout( "lease6_select", lease6_select_callout)); - CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); - Lease6Ptr lease; - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"), - Lease::TYPE_NA, false, false, "", false); - ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); - ctx.callout_handle_ = callout_handle; + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234)), + HooksManager::createCalloutHandle()); + ctx.currentIA().iaid_ = iaid_; + EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); // Check that we got a lease ASSERT_TRUE(lease); @@ -223,16 +222,12 @@ TEST_F(HookAllocEngine6Test, change_lease6_select) { EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout( "lease6_select", lease6_select_different_callout)); - // Normally, dhcpv6_srv would passed the handle when calling allocateLeases6, - // but in tests we need to create it on our own. - CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); - // Call allocateLeases6. Callouts should be triggered here. Lease6Ptr lease; - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"), - Lease::TYPE_NA, false, false, "", false); - ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); - ctx.callout_handle_ = callout_handle; + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, + Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234)), + HooksManager::createCalloutHandle()); + ctx.currentIA().iaid_ = iaid_; EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); // Check that we got a lease ASSERT_TRUE(lease); diff --git a/src/lib/dhcpsrv/tests/alloc_engine_utils.cc b/src/lib/dhcpsrv/tests/alloc_engine_utils.cc index 3237d2afd6..224a662c83 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine_utils.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine_utils.cc @@ -208,9 +208,13 @@ AllocEngine6Test::allocateTest(AllocEngine& engine, const Pool6Ptr& pool, Lease::Type type = pool->getType(); uint8_t expected_len = pool->getLength(); - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, hint, type, - false, false, "", fake); - ctx.query_.reset(new Pkt6(fake ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234)); + Pkt6Ptr query(new Pkt6(fake ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234)); + + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", + fake, query); + ctx.currentIA().iaid_ = iaid_; + ctx.currentIA().type_ = type; + ctx.currentIA().addHint(hint); Lease6Collection leases; @@ -266,14 +270,17 @@ AllocEngine6Test::simpleAlloc6Test(const Pool6Ptr& pool, const IOAddress& hint, return (Lease6Ptr()); } - Lease6Ptr lease; - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, hint, type, - false, false, "", fake); + Pkt6Ptr query(new Pkt6(fake ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234)); + + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", fake, query); ctx.hwaddr_ = hwaddr_; ctx.addHostIdentifier(Host::IDENT_HWADDR, hwaddr_->hwaddr_); - ctx.query_.reset(new Pkt6(fake ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234)); + ctx.currentIA().iaid_ = iaid_; + ctx.currentIA().type_ = type; + ctx.currentIA().addHint(hint); findReservation(*engine, ctx); + Lease6Ptr lease; EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); // Check that we got a lease @@ -315,11 +322,12 @@ AllocEngine6Test::renewTest(AllocEngine& engine, const Pool6Ptr& pool, Lease::Type type = pool->getType(); uint8_t expected_len = pool->getLength(); - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"), - type, false, false, "", false); - ctx.hints_ = hints; - ctx.query_.reset(new Pkt6(DHCPV6_RENEW, 123)); - ctx.query_.reset(new Pkt6(DHCPV6_RENEW, 1234)); + Pkt6Ptr query(new Pkt6(DHCPV6_RENEW, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", + false, query); + ctx.currentIA().hints_ = hints; + ctx.currentIA().iaid_ = iaid_; + ctx.currentIA().type_ = type; findReservation(engine, ctx); Lease6Collection leases = engine.renewLeases6(ctx); @@ -366,10 +374,15 @@ AllocEngine6Test::allocWithUsedHintTest(Lease::Type type, IOAddress used_addr, // Another client comes in and request an address that is in pool, but // unfortunately it is used already. The same address must not be allocated // twice. + + Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, + query); + ctx.currentIA().iaid_ = iaid_; + ctx.currentIA().type_ = type; + ctx.currentIA().addHint(requested); + Lease6Ptr lease; - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, requested, type, - false, false, "", false); - ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); // Check that we got a lease @@ -403,11 +416,15 @@ AllocEngine6Test::allocBogusHint6(Lease::Type type, asiolink::IOAddress hint, // Client would like to get a 3000::abc lease, which does not belong to any // supported lease. Allocation engine should ignore it and carry on // with the normal allocation - Lease6Ptr lease; - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, hint, type, false, - false, "", false); - ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234)); + Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, + query); + ctx.currentIA().iaid_ = iaid_; + ctx.currentIA().type_ = type; + ctx.currentIA().addHint(hint); + + Lease6Ptr lease; EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); // Check that we got a lease @@ -448,9 +465,12 @@ AllocEngine6Test::testReuseLease6(const AllocEnginePtr& engine, } // A client comes along, asking specifically for a given address - AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress(addr), - Lease::TYPE_NA, false, false, "", fake_allocation); - ctx.query_.reset(new Pkt6(fake_allocation ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234)); + + Pkt6Ptr query(new Pkt6(fake_allocation ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", + fake_allocation, query); + ctx.currentIA().iaid_ = iaid_; + ctx.currentIA().addHint(IOAddress(addr)); Lease6Collection leases; -- 2.47.2