Parcourir la source

[master] Merge branch 'trac3083'

Marcin Siodelski il y a 11 ans
Parent
commit
37af28303d

+ 6 - 2
src/bin/dhcp4/dhcp4_srv.cc

@@ -715,9 +715,13 @@ Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
     // will try to honour 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.
+    // @todo pass the actual FQDN data.
+    Lease4Ptr old_lease;
     Lease4Ptr lease = alloc_engine_->allocateAddress4(subnet, client_id, hwaddr,
-                                                      hint, fake_allocation,
-                                                      callout_handle);
+                                                      hint, false, false, "",
+                                                      fake_allocation,
+                                                      callout_handle,
+                                                      old_lease);
 
     if (lease) {
         // We have a lease! Let's set it in the packet and send it back to

+ 58 - 15
src/lib/dhcpsrv/alloc_engine.cc

@@ -93,7 +93,7 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
 
     // Let's get the last allocated address. It is usually set correctly,
     // but there are times when it won't be (like after removing a pool or
-    // perhaps restaring the server).
+    // perhaps restarting the server).
     IOAddress last = subnet->getLastAllocated();
 
     const PoolCollection& pools = subnet->getPools();
@@ -140,7 +140,7 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
         return (next);
     }
 
-    // there is a next pool, let's try first adddress from it
+    // there is a next pool, let's try first address from it
     next = (*it)->getFirstAddress();
     subnet->setLastAllocated(next);
     return (next);
@@ -330,8 +330,17 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
                               const ClientIdPtr& clientid,
                               const HWAddrPtr& hwaddr,
                               const IOAddress& hint,
+                              const bool fwd_dns_update,
+                              const bool rev_dns_update,
+                              const std::string& hostname,
                               bool fake_allocation,
-                              const isc::hooks::CalloutHandlePtr& callout_handle) {
+                              const isc::hooks::CalloutHandlePtr& callout_handle,
+                              Lease4Ptr& old_lease) {
+
+    // The NULL pointer indicates that the old lease didn't exist. It may
+    // be later set to non NULL value if existing lease is found in the
+    // database.
+    old_lease.reset();
 
     try {
         // Allocator is always created in AllocEngine constructor and there is
@@ -351,10 +360,13 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
         // Check if there's existing lease for that subnet/clientid/hwaddr combination.
         Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(*hwaddr, subnet->getID());
         if (existing) {
+            // Save the old lease, before renewal.
+            old_lease.reset(new Lease4(*existing));
             // We have a lease already. This is a returning client, probably after
             // its reboot.
-            existing = renewLease4(subnet, clientid, hwaddr, existing, callout_handle,
-                                   fake_allocation);
+            existing = renewLease4(subnet, clientid, hwaddr,
+                                   fwd_dns_update, rev_dns_update, hostname,
+                                   existing, callout_handle, fake_allocation);
             if (existing) {
                 return (existing);
             }
@@ -366,9 +378,13 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
         if (clientid) {
             existing = LeaseMgrFactory::instance().getLease4(*clientid, subnet->getID());
             if (existing) {
+                // Save the old lease before renewal.
+                old_lease.reset(new Lease4(*existing));
                 // we have a lease already. This is a returning client, probably after
                 // its reboot.
-                existing = renewLease4(subnet, clientid, hwaddr, existing, callout_handle,
+                existing = renewLease4(subnet, clientid, hwaddr,
+                                       fwd_dns_update, rev_dns_update,
+                                       hostname, existing, callout_handle,
                                        fake_allocation);
                 // @todo: produce a warning. We haven't found him using MAC address, but
                 // we found him using client-id
@@ -387,7 +403,9 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
 
                 // The hint is valid and not currently used, let's create a lease for it
                 Lease4Ptr lease = createLease4(subnet, clientid, hwaddr, hint,
-                                               callout_handle, fake_allocation);
+                                               fwd_dns_update, rev_dns_update,
+                                               hostname, callout_handle,
+                                               fake_allocation);
 
                 // It can happen that the lease allocation failed (we could have lost
                 // the race condition. That means that the hint is lo longer usable and
@@ -397,8 +415,12 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
                 }
             } else {
                 if (existing->expired()) {
+                    // Save the old lease, before reusing it.
+                    old_lease.reset(new Lease4(*existing));
                     return (reuseExpiredLease(existing, subnet, clientid, hwaddr,
-                                              callout_handle, fake_allocation));
+                                              fwd_dns_update, rev_dns_update,
+                                              hostname, callout_handle,
+                                              fake_allocation));
                 }
 
             }
@@ -431,7 +453,9 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
             if (!existing) {
                 // there's no existing lease for selected candidate, so it is
                 // free. Let's allocate it.
-                Lease4Ptr lease = createLease4(subnet, clientid, hwaddr, candidate,
+                Lease4Ptr lease = createLease4(subnet, clientid, hwaddr,
+                                               candidate, fwd_dns_update,
+                                               rev_dns_update, hostname,
                                                callout_handle, fake_allocation);
                 if (lease) {
                     return (lease);
@@ -442,8 +466,12 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
                 // allocation attempts.
             } else {
                 if (existing->expired()) {
+                    // Save old lease before reusing it.
+                    old_lease.reset(new Lease4(*existing));
                     return (reuseExpiredLease(existing, subnet, clientid, hwaddr,
-                                              callout_handle, fake_allocation));
+                                              fwd_dns_update, rev_dns_update,
+                                              hostname, callout_handle,
+                                              fake_allocation));
                 }
             }
 
@@ -466,6 +494,9 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
 Lease4Ptr AllocEngine::renewLease4(const SubnetPtr& subnet,
                                    const ClientIdPtr& clientid,
                                    const HWAddrPtr& hwaddr,
+                                   const bool fwd_dns_update,
+                                   const bool rev_dns_update,
+                                   const std::string& hostname,
                                    const Lease4Ptr& lease,
                                    const isc::hooks::CalloutHandlePtr& callout_handle,
                                    bool fake_allocation /* = false */) {
@@ -487,6 +518,9 @@ Lease4Ptr AllocEngine::renewLease4(const SubnetPtr& subnet,
     lease->t1_ = subnet->getT1();
     lease->t2_ = subnet->getT2();
     lease->valid_lft_ = subnet->getValid();
+    lease->fqdn_fwd_ = fwd_dns_update;
+    lease->fqdn_rev_ = rev_dns_update;
+    lease->hostname_ = hostname;
 
     bool skip = false;
     // Execute all callouts registered for packet6_send
@@ -615,6 +649,9 @@ Lease4Ptr AllocEngine::reuseExpiredLease(Lease4Ptr& expired,
                                          const SubnetPtr& subnet,
                                          const ClientIdPtr& clientid,
                                          const HWAddrPtr& hwaddr,
+                                         const bool fwd_dns_update,
+                                         const bool rev_dns_update,
+                                         const std::string& hostname,
                                          const isc::hooks::CalloutHandlePtr& callout_handle,
                                          bool fake_allocation /*= false */ ) {
 
@@ -631,9 +668,9 @@ Lease4Ptr AllocEngine::reuseExpiredLease(Lease4Ptr& expired,
     expired->cltt_ = time(NULL);
     expired->subnet_id_ = subnet->getID();
     expired->fixed_ = false;
-    expired->hostname_ = std::string("");
-    expired->fqdn_fwd_ = false;
-    expired->fqdn_rev_ = false;
+    expired->hostname_ = hostname;
+    expired->fqdn_fwd_ = fwd_dns_update;
+    expired->fqdn_rev_ = rev_dns_update;
 
     /// @todo: log here that the lease was reused (there's ticket #2524 for
     /// logging in libdhcpsrv)
@@ -771,6 +808,9 @@ Lease4Ptr AllocEngine::createLease4(const SubnetPtr& subnet,
                                     const DuidPtr& clientid,
                                     const HWAddrPtr& hwaddr,
                                     const IOAddress& addr,
+                                    const bool fwd_dns_update,
+                                    const bool rev_dns_update,
+                                    const std::string& hostname,
                                     const isc::hooks::CalloutHandlePtr& callout_handle,
                                     bool fake_allocation /*= false */ ) {
     if (!hwaddr) {
@@ -789,6 +829,11 @@ Lease4Ptr AllocEngine::createLease4(const SubnetPtr& subnet,
                                subnet->getT1(), subnet->getT2(), now,
                                subnet->getID()));
 
+    // Set FQDN specific lease parameters.
+    lease->fqdn_fwd_ = fwd_dns_update;
+    lease->fqdn_rev_ = rev_dns_update;
+    lease->hostname_ = hostname;
+
     // Let's execute all callouts registered for lease4_select
     if (callout_handle &&
         HooksManager::getHooksManager().calloutsPresent(hook_index_lease4_select_)) {
@@ -827,8 +872,6 @@ Lease4Ptr AllocEngine::createLease4(const SubnetPtr& subnet,
         callout_handle->getArgument("lease4", lease);
     }
 
-
-
     if (!fake_allocation) {
         // That is a real (REQUEST) allocation
         bool status = LeaseMgrFactory::instance().addLease(lease);

+ 99 - 33
src/lib/dhcpsrv/alloc_engine.h

@@ -182,28 +182,63 @@ protected:
     ///        we give up (0 means unlimited)
     AllocEngine(AllocType engine_type, unsigned int attempts);
 
-    /// @brief Allocates an IPv4 lease
+    /// @brief Returns IPv4 lease.
     ///
-    /// This method uses currently selected allocator to pick an address from
-    /// specified subnet, creates a lease for that address and then inserts
-    /// it into LeaseMgr (if this allocation is not fake).
+    /// This method finds the appropriate lease for the client using the
+    /// following algorithm:
+    /// - If lease exists for the combination of the HW address, client id and
+    /// subnet, try to renew a lease and return it.
+    /// - If lease exists for the combination of the client id and subnet, try
+    /// to renew the lease and return it.
+    /// - If client supplied an address hint and this address is available,
+    /// allocate the new lease with this address.
+    /// - If client supplied an address hint and the lease for this address
+    /// exists in the database, return this lease if it is expired.
+    /// - Pick new address from the pool and try to allocate it for the client,
+    /// if expired lease exists for the picked address, try to reuse this lease.
+    ///
+    /// When a server should do DNS updates, it is required that allocation
+    /// returns the information how the lease was obtained by the allocation
+    /// engine. In particular, the DHCP server should be able to check whether
+    /// existing lease was returned, or new lease was allocated. When existing
+    /// lease was returned, server should check whether the FQDN has changed
+    /// between the allocation of the old and new lease. If so, server should
+    /// perform appropriate DNS update. If not, server may choose to not
+    /// perform the update. The information about the old lease is returned via
+    /// @c old_lease parameter. If NULL value is returned, it is an indication
+    /// that new lease was allocated for the client. If non-NULL value is
+    /// returned, it is an indication that allocation engine reused/renewed an
+    /// existing lease.
     ///
     /// @param subnet subnet the allocation should come from
     /// @param clientid Client identifier
-    /// @param hwaddr client's hardware address info
-    /// @param hint a hint that the client provided
-    /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
+    /// @param hwaddr Client's hardware address info
+    /// @param hint A hint that the client provided
+    /// @param fwd_dns_update Indicates whether forward DNS update will be
+    ///        performed for the client (true) or not (false).
+    /// @param rev_dns_update Indicates whether reverse DNS update will be
+    ///        performed for the client (true) or not (false).
+    /// @param hostname A string carrying hostname to be used for DNS updates.
+    /// @param fake_allocation Is this real i.e. REQUEST (false) or just picking
     ///        an address for DISCOVER that is not really allocated (true)
-    /// @param callout_handle a callout handle (used in hooks). A lease callouts
+    /// @param callout_handle A callout handle (used in hooks). A lease callouts
     ///        will be executed if this parameter is passed.
+    /// @param [out] old_lease Holds the pointer to a previous instance of a
+    ///        lease. The NULL pointer indicates that lease didn't exist prior
+    ///        to calling this function (e.g. new lease has been allocated).
+    ///
     /// @return Allocated IPv4 lease (or NULL if allocation failed)
     Lease4Ptr
     allocateAddress4(const SubnetPtr& subnet,
                      const ClientIdPtr& clientid,
                      const HWAddrPtr& hwaddr,
                      const isc::asiolink::IOAddress& hint,
+                     const bool fwd_dns_update,
+                     const bool rev_dns_update,
+                     const std::string& hostname,
                      bool fake_allocation,
-                     const isc::hooks::CalloutHandlePtr& callout_handle);
+                     const isc::hooks::CalloutHandlePtr& callout_handle,
+                     Lease4Ptr& old_lease);
 
     /// @brief Renews a IPv4 lease
     ///
@@ -214,18 +249,26 @@ protected:
     /// to get a new lease. It thinks that it gets a new lease, but in fact
     /// we are only renewing the still valid lease for that client.
     ///
-    /// @param subnet subnet the client is attached to
-    /// @param clientid client identifier
-    /// @param hwaddr client's hardware address
-    /// @param lease lease to be renewed
+    /// @param subnet A subnet the client is attached to
+    /// @param clientid Client identifier
+    /// @param hwaddr Client's hardware address
+    /// @param fwd_dns_update Indicates whether forward DNS update will be
+    ///        performed for the client (true) or not (false).
+    /// @param rev_dns_update Indicates whether reverse DNS update will be
+    ///        performed for the client (true) or not (false).
+    /// @param hostname A string carrying hostname to be used for DNS updates.
+    /// @param lease A lease to be renewed
     /// @param callout_handle a callout handle (used in hooks). A lease callouts
     ///        will be executed if this parameter is passed.
-    /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
+    /// @param fake_allocation Is this real i.e. REQUEST (false) or just picking
     ///        an address for DISCOVER that is not really allocated (true)
     Lease4Ptr
     renewLease4(const SubnetPtr& subnet,
                 const ClientIdPtr& clientid,
                 const HWAddrPtr& hwaddr,
+                const bool fwd_dns_update,
+                const bool rev_dns_update,
+                const std::string& hostname,
                 const Lease4Ptr& lease,
                 const isc::hooks::CalloutHandlePtr& callout_handle,
                 bool fake_allocation /* = false */);
@@ -241,9 +284,11 @@ protected:
     /// @param iaid iaid field from the IA_NA container that client sent
     /// @param hint a hint that the client provided
     /// @param fwd_dns_update A boolean value which indicates that server takes
-    /// responisibility for the forward DNS Update for this lease (if true).
+    ///        responsibility for the forward DNS Update for this lease
+    ///        (if true).
     /// @param rev_dns_update A boolean value which indicates that server takes
-    /// responibility for the reverse DNS Update for this lease (if true).
+    ///        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)
@@ -272,20 +317,28 @@ private:
     /// into the database. That may fail in some cases, e.g. when there is another
     /// allocation process and we lost a race to a specific lease.
     ///
-    /// @param subnet subnet the lease is allocated from
-    /// @param clientid client identifier
-    /// @param hwaddr client's hardware address
-    /// @param addr an address that was selected and is confirmed to be available
+    /// @param subnet Subnet the lease is allocated from
+    /// @param clientid Client identifier
+    /// @param hwaddr Client's hardware address
+    /// @param addr An address that was selected and is confirmed to be available
+    /// @param fwd_dns_update Indicates whether forward DNS update will be
+    ///        performed for the client (true) or not (false).
+    /// @param rev_dns_update Indicates whether reverse DNS update will be
+    ///        performed for the client (true) or not (false).
+    /// @param hostname A string carrying hostname to be used for DNS updates.
     /// @param callout_handle a callout handle (used in hooks). A lease callouts
     ///        will be executed if this parameter is passed (and there are callouts
     ///        registered)
-    /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
+    /// @param fake_allocation Is this real i.e. REQUEST (false) or just picking
     ///        an address for DISCOVER that is not really allocated (true)
     /// @return allocated lease (or NULL in the unlikely case of the lease just
     ///        becomed unavailable)
     Lease4Ptr createLease4(const SubnetPtr& subnet, const DuidPtr& clientid,
                            const HWAddrPtr& hwaddr,
                            const isc::asiolink::IOAddress& addr,
+                           const bool fwd_dns_update,
+                           const bool rev_dns_update,
+                           const std::string& hostname,
                            const isc::hooks::CalloutHandlePtr& callout_handle,
                            bool fake_allocation = false);
 
@@ -301,9 +354,11 @@ private:
     /// @param addr an address that was selected and is confirmed to be
     /// available
     /// @param fwd_dns_update A boolean value which indicates that server takes
-    /// responisibility for the forward DNS Update for this lease (if true).
+    ///        responsibility for the forward DNS Update for this lease
+    ///        (if true).
     /// @param rev_dns_update A boolean value which indicates that server takes
-    /// responibility for the reverse DNS Update for this lease (if true).
+    ///        responsibility for the reverse DNS Update for this lease
+    ///        (if true).
     /// @param hostname A fully qualified domain-name of the client.
     /// @param callout_handle a callout handle (used in hooks). A lease callouts
     ///        will be executed if this parameter is passed (and there are callouts
@@ -311,7 +366,7 @@ private:
     /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
     ///        an address for SOLICIT that is not really allocated (true)
     /// @return allocated lease (or NULL in the unlikely case of the lease just
-    ///        becomed unavailable)
+    ///         became unavailable)
     Lease6Ptr createLease6(const Subnet6Ptr& subnet, const DuidPtr& duid,
                            uint32_t iaid, const isc::asiolink::IOAddress& addr,
                            const bool fwd_dns_update, const bool rev_dns_update,
@@ -325,19 +380,28 @@ private:
     /// is updated if this is real (i.e. REQUEST, fake_allocation = false), not
     /// dummy allocation request (i.e. DISCOVER, fake_allocation = true).
     ///
-    /// @param expired old, expired lease
-    /// @param subnet subnet the lease is allocated from
-    /// @param clientid client identifier
-    /// @param hwaddr client's hardware address
-    /// @param callout_handle a callout handle (used in hooks). A lease callouts
+    /// @param expired Old, expired lease
+    /// @param subnet Subnet the lease is allocated from
+    /// @param clientid Client identifier
+    /// @param hwaddr Client's hardware address
+    /// @param fwd_dns_update Indicates whether forward DNS update will be
+    ///        performed for the client (true) or not (false).
+    /// @param rev_dns_update Indicates whether reverse DNS update will be
+    ///        performed for the client (true) or not (false).
+    /// @param hostname A string carrying hostname to be used for DNS updates.
+    /// @param callout_handle A callout handle (used in hooks). A lease callouts
     ///        will be executed if this parameter is passed.
-    /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
+    /// @param fake_allocation Is this real i.e. REQUEST (false) or just picking
     ///        an address for DISCOVER that is not really allocated (true)
     /// @return refreshed lease
     /// @throw BadValue if trying to recycle lease that is still valid
-    Lease4Ptr reuseExpiredLease(Lease4Ptr& expired, const SubnetPtr& subnet,
+    Lease4Ptr reuseExpiredLease(Lease4Ptr& expired,
+                                const SubnetPtr& subnet,
                                 const ClientIdPtr& clientid,
                                 const HWAddrPtr& hwaddr,
+                                const bool fwd_dns_update,
+                                const bool rev_dns_update,
+                                const std::string& hostname,
                                 const isc::hooks::CalloutHandlePtr& callout_handle,
                                 bool fake_allocation = false);
 
@@ -352,9 +416,11 @@ private:
     /// @param duid client's DUID
     /// @param iaid IAID from the IA_NA container the client sent to us
     /// @param fwd_dns_update A boolean value which indicates that server takes
-    /// responisibility for the forward DNS Update for this lease (if true).
+    ///        responsibility for the forward DNS Update for this lease
+    ///        (if true).
     /// @param rev_dns_update A boolean value which indicates that server takes
-    /// responibility for the reverse DNS Update for this lease (if true).
+    ///        responsibility for the reverse DNS Update for this lease
+    ///        (if true).
     /// @param hostname A fully qualified domain-name of the client.
     /// @param callout_handle a callout handle (used in hooks). A lease callouts
     ///        will be executed if this parameter is passed.

+ 46 - 0
src/lib/dhcpsrv/lease_mgr.cc

@@ -38,6 +38,52 @@ Lease::Lease(const isc::asiolink::IOAddress& addr, uint32_t t1, uint32_t t2,
      subnet_id_(subnet_id), fixed_(false), fqdn_fwd_(false), fqdn_rev_(false) {
 }
 
+Lease4::Lease4(const Lease4& other)
+    : Lease(other.addr_, other.t1_, other.t2_, other.valid_lft_,
+            other.subnet_id_, other.cltt_), ext_(other.ext_),
+      hwaddr_(other.hwaddr_) {
+
+    fixed_ = other.fixed_;
+    fqdn_fwd_ = other.fqdn_fwd_;
+    fqdn_rev_ = other.fqdn_rev_;
+    hostname_ = other.hostname_;
+    comments_ = other.comments_;
+
+    if (other.client_id_) {
+        client_id_.reset(new ClientId(other.client_id_->getClientId()));
+
+    } else {
+        client_id_.reset();
+
+    }
+}
+
+Lease4&
+Lease4::operator=(const Lease4& other) {
+    if (this != &other) {
+        addr_ = other.addr_;
+        t1_ = other.t1_;
+        t2_ = other.t2_;
+        valid_lft_ = other.valid_lft_;
+        cltt_ = other.cltt_;
+        subnet_id_ = other.subnet_id_;
+        fixed_ = other.fixed_;
+        hostname_ = other.hostname_;
+        fqdn_fwd_ = other.fqdn_fwd_;
+        fqdn_rev_ = other.fqdn_rev_;
+        comments_ = other.comments_;
+        ext_ = other.ext_;
+        hwaddr_ = other.hwaddr_;
+
+        if (other.client_id_) {
+            client_id_.reset(new ClientId(other.client_id_->getClientId()));
+        } else {
+            client_id_.reset();
+        }
+    }
+    return (*this);
+}
+
 Lease6::Lease6(LeaseType type, const isc::asiolink::IOAddress& addr,
                DuidPtr duid, uint32_t iaid, uint32_t preferred, uint32_t valid,
                uint32_t t1, uint32_t t2, SubnetID subnet_id, uint8_t prefixlen)

+ 11 - 1
src/lib/dhcpsrv/lease_mgr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -259,6 +259,16 @@ struct Lease4 : public Lease {
     Lease4() : Lease(0, 0, 0, 0, 0, 0) {
     }
 
+    /// @brief Copy constructor
+    ///
+    /// @param other the @c Lease4 object to be copied.
+    Lease4(const Lease4& other);
+
+    /// @brief Assignment operator.
+    ///
+    /// @param other the @c Lease4 object to be assigned.
+    Lease4& operator=(const Lease4& other);
+
     /// @brief Compare two leases for equality
     ///
     /// @param other lease6 object with which to compare

+ 19 - 8
src/lib/dhcpsrv/memfile_lease_mgr.cc

@@ -62,7 +62,7 @@ Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) cons
     if (l == storage4_.end()) {
         return (Lease4Ptr());
     } else {
-        return (*l);
+        return (Lease4Ptr(new Lease4(**l)));
     }
 }
 
@@ -94,7 +94,7 @@ Lease4Ptr Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr,
     }
 
     // Lease was found. Return it to the caller.
-    return (*lease);
+    return (Lease4Ptr(new Lease4(**lease)));
 }
 
 Lease4Collection Memfile_LeaseMgr::getLease4(const ClientId& clientid) const {
@@ -123,11 +123,11 @@ Lease4Ptr Memfile_LeaseMgr::getLease4(const ClientId& client_id,
         return Lease4Ptr();
     }
     // Lease was found. Return it to the caller.
-    return (*lease);
+    return (Lease4Ptr(new Lease4(**lease)));
 }
 
-Lease6Ptr Memfile_LeaseMgr::getLease6(
-        const isc::asiolink::IOAddress& addr) const {
+Lease6Ptr
+Memfile_LeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_GET_ADDR6).arg(addr.toText());
 
@@ -135,7 +135,7 @@ Lease6Ptr Memfile_LeaseMgr::getLease6(
     if (l == storage6_.end()) {
         return (Lease6Ptr());
     } else {
-        return (*l);
+        return (Lease6Ptr(new Lease6(**l)));
     }
 }
 
@@ -167,20 +167,31 @@ Lease6Ptr Memfile_LeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
         return (Lease6Ptr());
     }
     // Lease was found, return it to the caller.
-    return (*lease);
+    return (Lease6Ptr(new Lease6(**lease)));
 }
 
 void Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
 
+    Lease4Storage::iterator lease_it = storage4_.find(lease->addr_);
+    if (lease_it == storage4_.end()) {
+        isc_throw(NoSuchLease, "failed to update the lease with address "
+                  << lease->addr_.toText() << " - no such lease");
+    }
+    **lease_it = *lease;
 }
 
 void Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
 
-
+    Lease6Storage::iterator lease_it = storage6_.find(lease->addr_);
+    if (lease_it == storage6_.end()) {
+        isc_throw(NoSuchLease, "failed to update the lease with address "
+                  << lease->addr_.toText() << " - no such lease");
+    }
+    **lease_it = *lease;
 }
 
 bool Memfile_LeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {

+ 23 - 12
src/lib/dhcpsrv/memfile_lease_mgr.h

@@ -65,8 +65,10 @@ public:
 
     /// @brief Returns existing IPv4 lease for specified IPv4 address.
     ///
-    /// @todo Not implemented yet
-    /// @param addr address of the searched lease
+    /// This function returns a copy of the lease. The modification in the
+    /// return lease does not affect the instance held in the lease storage.
+    ///
+    /// @param addr An address of the searched lease.
     ///
     /// @return a collection of leases
     virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const;
@@ -85,10 +87,11 @@ public:
     /// @return lease collection
     virtual Lease4Collection getLease4(const isc::dhcp::HWAddr& hwaddr) const;
 
-    /// @brief Returns existing IPv4 leases for specified hardware address
+    /// @brief Returns existing IPv4 lease for specified hardware address
     ///        and a subnet
     ///
-    /// @todo Not implemented yet
+    /// This function returns a copy of the lease. The modification in the
+    /// return lease does not affect the instance held in the lease storage.
     ///
     /// There can be at most one lease for a given HW address in a single
     /// pool, so this method with either return a single lease or NULL.
@@ -109,11 +112,12 @@ public:
 
     /// @brief Returns existing IPv4 lease for specified client-id
     ///
+    /// This function returns a copy of the lease. The modification in the
+    /// return lease does not affect the instance held in the lease storage.
+    ///
     /// There can be at most one lease for a given HW address in a single
     /// pool, so this method with either return a single lease or NULL.
     ///
-    /// @todo Not implemented yet
-    ///
     /// @param clientid client identifier
     /// @param subnet_id identifier of the subnet that lease must belong to
     ///
@@ -123,7 +127,10 @@ public:
 
     /// @brief Returns existing IPv6 lease for a given IPv6 address.
     ///
-    /// @param addr address of the searched lease
+    /// This function returns a copy of the lease. The modification in the
+    /// return lease does not affect the instance held in the lease storage.
+    ///
+    /// @param addr An address of the searched lease.
     ///
     /// @return smart pointer to the lease (or NULL if a lease is not found)
     virtual Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const;
@@ -140,27 +147,31 @@ public:
 
     /// @brief Returns existing IPv6 lease for a given DUID+IA combination
     ///
-    /// @todo Not implemented yet
+    /// This function returns a copy of the lease. The modification in the
+    /// return lease does not affect the instance held in the lease storage.
     ///
     /// @param duid client DUID
     /// @param iaid IA identifier
     /// @param subnet_id identifier of the subnet the lease must belong to
     ///
     /// @return smart pointer to the lease (or NULL if a lease is not found)
-    virtual Lease6Ptr getLease6(const DUID& duid, uint32_t iaid, SubnetID subnet_id) const;
+    virtual Lease6Ptr getLease6(const DUID& duid, uint32_t iaid,
+                                SubnetID subnet_id) const;
 
     /// @brief Updates IPv4 lease.
     ///
-    /// @todo Not implemented yet
+    /// @warning This function does not validate the pointer to the lease.
+    /// It is caller's responsibility to pass the valid pointer.
     ///
     /// @param lease4 The lease to be updated.
     ///
     /// If no such lease is present, an exception will be thrown.
     virtual void updateLease4(const Lease4Ptr& lease4);
 
-    /// @brief Updates IPv4 lease.
+    /// @brief Updates IPv6 lease.
     ///
-    /// @todo Not implemented yet
+    /// @warning This function does not validate the pointer to the lease.
+    /// It is caller's responsibility to pass the valid pointer.
     ///
     /// @param lease6 The lease to be updated.
     ///

+ 118 - 33
src/lib/dhcpsrv/tests/alloc_engine_unittest.cc

@@ -164,8 +164,6 @@ public:
         EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
         EXPECT_EQ(subnet_->getT1(), lease->t1_);
         EXPECT_EQ(subnet_->getT2(), lease->t2_);
-        EXPECT_TRUE(false == lease->fqdn_fwd_);
-        EXPECT_TRUE(false == lease->fqdn_rev_);
         if (lease->client_id_ && !clientid_) {
             ADD_FAILURE() << "Lease4 has a client-id, while it should have none.";
         } else
@@ -188,6 +186,7 @@ public:
     Subnet4Ptr subnet_;       ///< Subnet4 (used in tests)
     Pool4Ptr pool_;           ///< Pool belonging to subnet_
     LeaseMgrFactory factory_; ///< Pointer to LeaseMgr factory
+    Lease4Ptr old_lease_;     ///< Holds previous instance of the lease.
 };
 
 // This test checks if the Allocation Engine can be instantiated and that it
@@ -612,8 +611,13 @@ TEST_F(AllocEngine4Test, simpleAlloc4) {
     ASSERT_TRUE(engine);
 
     Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
-                                               IOAddress("0.0.0.0"), false,
-                                               CalloutHandlePtr());
+                                               IOAddress("0.0.0.0"),
+                                               false, true,
+                                               "somehost.example.com.",
+                                               false, CalloutHandlePtr(),
+                                               old_lease_);
+    // The new lease has been allocated, so the old lease should not exist.
+    EXPECT_FALSE(old_lease_);
 
     // Check that we got a lease
     ASSERT_TRUE(lease);
@@ -636,8 +640,13 @@ TEST_F(AllocEngine4Test, fakeAlloc4) {
     ASSERT_TRUE(engine);
 
     Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
-                                               IOAddress("0.0.0.0"), true,
-                                               CalloutHandlePtr());
+                                               IOAddress("0.0.0.0"),
+                                               false, true, "host.example.com.",
+                                               true, CalloutHandlePtr(),
+                                               old_lease_);
+
+    // The new lease has been allocated, so the old lease should not exist.
+    EXPECT_FALSE(old_lease_);
 
     // Check that we got a lease
     ASSERT_TRUE(lease);
@@ -660,11 +669,15 @@ TEST_F(AllocEngine4Test, allocWithValidHint4) {
 
     Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
                                                IOAddress("192.0.2.105"),
-                                               false, CalloutHandlePtr());
-
+                                               true, true, "host.example.com.",
+                                               false, CalloutHandlePtr(),
+                                               old_lease_);
     // Check that we got a lease
     ASSERT_TRUE(lease);
 
+    // We have allocated the new lease, so the old lease should not exist.
+    EXPECT_FALSE(old_lease_);
+
     // We should get what we asked for
     EXPECT_EQ(lease->addr_.toText(), "192.0.2.105");
 
@@ -700,7 +713,13 @@ TEST_F(AllocEngine4Test, allocWithUsedHint4) {
     // twice.
     Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
                                                IOAddress("192.0.2.106"),
-                                               false, CalloutHandlePtr());
+                                               false, false, "",
+                                               false, CalloutHandlePtr(),
+                                               old_lease_);
+
+    // New lease has been allocated, so the old lease should not exist.
+    EXPECT_FALSE(old_lease_);
+
     // Check that we got a lease
     ASSERT_TRUE(lease);
 
@@ -734,10 +753,15 @@ TEST_F(AllocEngine4Test, allocBogusHint4) {
     // with the normal allocation
     Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
                                                IOAddress("10.1.1.1"),
-                                               false, CalloutHandlePtr());
+                                               false, false, "",
+                                               false, CalloutHandlePtr(),
+                                               old_lease_);
     // Check that we got a lease
     ASSERT_TRUE(lease);
 
+    // We have allocated a new lease, so the old lease should not exist.
+    EXPECT_FALSE(old_lease_);
+
     // We should NOT get what we asked for, because it is used already
     EXPECT_TRUE(lease->addr_.toText() != "10.1.1.1");
 
@@ -761,21 +785,32 @@ TEST_F(AllocEngine4Test, allocateAddress4Nulls) {
 
     // Allocations without subnet are not allowed
     Lease4Ptr lease = engine->allocateAddress4(SubnetPtr(), clientid_, hwaddr_,
-                                               IOAddress("0.0.0.0"), false,
-                                               CalloutHandlePtr());
+                                               IOAddress("0.0.0.0"),
+                                               false, false, "",
+                                               false, CalloutHandlePtr(),
+                                               old_lease_);
     EXPECT_FALSE(lease);
 
     // Allocations without HW address are not allowed
     lease = engine->allocateAddress4(subnet_, clientid_, HWAddrPtr(),
-                                     IOAddress("0.0.0.0"), false, CalloutHandlePtr());
+                                     IOAddress("0.0.0.0"),
+                                     false, false, "",
+                                     false, CalloutHandlePtr(),
+                                     old_lease_);
     EXPECT_FALSE(lease);
+    EXPECT_FALSE(old_lease_);
 
     // Allocations without client-id are allowed
     clientid_ = ClientIdPtr();
     lease = engine->allocateAddress4(subnet_, ClientIdPtr(), hwaddr_,
-                                     IOAddress("0.0.0.0"), false, CalloutHandlePtr());
+                                     IOAddress("0.0.0.0"),
+                                     true, true, "myhost.example.com.",
+                                     false, CalloutHandlePtr(),
+                                     old_lease_);
     // Check that we got a lease
     ASSERT_TRUE(lease);
+    // New lease has been allocated, so the old lease should not exist.
+    EXPECT_FALSE(old_lease_);
 
     // Do all checks on the lease
     checkLease4(lease);
@@ -876,12 +911,18 @@ TEST_F(AllocEngine4Test, smallPool4) {
     subnet_->addPool(pool_);
     cfg_mgr.addSubnet4(subnet_);
 
-    Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
-                                               false, CalloutHandlePtr());
+    Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
+                                               IOAddress("0.0.0.0"),
+                                               true, true, "host.example.com.",
+                                               false, CalloutHandlePtr(),
+                                               old_lease_);
 
     // Check that we got that single lease
     ASSERT_TRUE(lease);
 
+    // We have allocated new lease, so the old lease should not exist.
+    EXPECT_FALSE(old_lease_);
+
     EXPECT_EQ("192.0.2.17", lease->addr_.toText());
 
     // Do all checks on the lease
@@ -916,8 +957,9 @@ TEST_F(AllocEngine4Test, outOfAddresses4) {
     uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
     uint8_t clientid2[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
     time_t now = time(NULL);
-    Lease4Ptr lease(new Lease4(addr, hwaddr2, sizeof(hwaddr2), clientid2, sizeof(clientid2),
-                               501, 502, 503, now, subnet_->getID()));
+    Lease4Ptr lease(new Lease4(addr, hwaddr2, sizeof(hwaddr2), clientid2,
+                               sizeof(clientid2), 501, 502, 503, now,
+                               subnet_->getID()));
     lease->cltt_ = time(NULL) - 10; // Allocated 10 seconds ago
     ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
 
@@ -925,9 +967,12 @@ TEST_F(AllocEngine4Test, outOfAddresses4) {
     // else, so the allocation should fail
 
     Lease4Ptr lease2 = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
-                                                IOAddress("0.0.0.0"), false,
-                                                CalloutHandlePtr());
+                                                IOAddress("0.0.0.0"),
+                                                false, false, "",
+                                                false, CalloutHandlePtr(),
+                                                old_lease_);
     EXPECT_FALSE(lease2);
+    EXPECT_FALSE(old_lease_);
 }
 
 // This test checks if an expired lease can be reused in DISCOVER (fake allocation)
@@ -950,29 +995,51 @@ TEST_F(AllocEngine4Test, discoverReuseExpiredLease4) {
     uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
     uint8_t clientid2[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
     time_t now = time(NULL) - 500; // Allocated 500 seconds ago
-    Lease4Ptr lease(new Lease4(addr, clientid2, sizeof(clientid2), hwaddr2, sizeof(hwaddr2),
+    Lease4Ptr lease(new Lease4(addr, clientid2, sizeof(clientid2),
+                               hwaddr2, sizeof(hwaddr2),
                                495, 100, 200, now, subnet_->getID()));
+    // Copy the lease, so as it can be compared with the old lease returned
+    // by the allocation engine.
+    Lease4 original_lease(*lease);
+
     // Lease was assigned 500 seconds ago, but its valid lifetime is 495, so it
     // is expired already
     ASSERT_TRUE(lease->expired());
     ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
 
     // CASE 1: Asking for any address
-    lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
-                                     true, CalloutHandlePtr());
+    lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
+                                     IOAddress("0.0.0.0"),
+                                     false, false, "",
+                                     true, CalloutHandlePtr(),
+                                     old_lease_);
     // Check that we got that single lease
     ASSERT_TRUE(lease);
     EXPECT_EQ(addr.toText(), lease->addr_.toText());
 
+    // We are reusing expired lease, the old (expired) instance should be
+    // returned. The returned instance should be the same as the original
+    // lease.
+    ASSERT_TRUE(old_lease_);
+    EXPECT_TRUE(original_lease == *old_lease_);
+
     // Do all checks on the lease (if subnet-id, preferred/valid times are ok etc.)
     checkLease4(lease);
 
     // CASE 2: Asking specifically for this address
-    lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_, IOAddress(addr.toText()),
-                                     true, CalloutHandlePtr());
+    lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
+                                     IOAddress(addr.toText()),
+                                     false, false, "",
+                                     true, CalloutHandlePtr(),
+                                     old_lease_);
     // Check that we got that single lease
     ASSERT_TRUE(lease);
     EXPECT_EQ(addr.toText(), lease->addr_.toText());
+
+    // We are updating expired lease. The copy of the old lease should be
+    // returned and it should be equal to the original lease.
+    ASSERT_TRUE(old_lease_);
+    EXPECT_TRUE(*old_lease_ == original_lease);
 }
 
 // This test checks if an expired lease can be reused in REQUEST (actual allocation)
@@ -987,8 +1054,13 @@ TEST_F(AllocEngine4Test, requestReuseExpiredLease4) {
     uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
     uint8_t clientid2[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
     time_t now = time(NULL) - 500; // Allocated 500 seconds ago
-    Lease4Ptr lease(new Lease4(addr, clientid2, sizeof(clientid2), hwaddr2, sizeof(hwaddr2),
-                               495, 100, 200, now, subnet_->getID()));
+    Lease4Ptr lease(new Lease4(addr, clientid2, sizeof(clientid2), hwaddr2,
+                               sizeof(hwaddr2), 495, 100, 200, now,
+                               subnet_->getID()));
+    // Make a copy of the lease, so as we can comapre that with the old lease
+    // instance returned by the allocation engine.
+    Lease4 original_lease(*lease);
+
     // Lease was assigned 500 seconds ago, but its valid lifetime is 495, so it
     // is expired already
     ASSERT_TRUE(lease->expired());
@@ -996,8 +1068,10 @@ TEST_F(AllocEngine4Test, requestReuseExpiredLease4) {
 
     // A client comes along, asking specifically for this address
     lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
-                                     IOAddress(addr.toText()), false,
-                                     CalloutHandlePtr());
+                                     IOAddress(addr.toText()),
+                                     false, true, "host.example.com.",
+                                     false, CalloutHandlePtr(),
+                                     old_lease_);
 
     // Check that he got that single lease
     ASSERT_TRUE(lease);
@@ -1009,6 +1083,11 @@ TEST_F(AllocEngine4Test, requestReuseExpiredLease4) {
 
     // Now check that the lease in LeaseMgr has the same parameters
     detailCompareLease(lease, from_mgr);
+
+    // The allocation engine should return a copy of the old lease. This
+    // lease should be equal to the original lease.
+    ASSERT_TRUE(old_lease_);
+    EXPECT_TRUE(*old_lease_ == original_lease);
 }
 
 /// @todo write renewLease6
@@ -1039,7 +1118,8 @@ TEST_F(AllocEngine4Test, renewLease4) {
     // Lease was assigned 45 seconds ago and is valid for 100 seconds. Let's
     // renew it.
     ASSERT_FALSE(lease->expired());
-    lease = engine->renewLease4(subnet_, clientid_, hwaddr_, lease,
+    lease = engine->renewLease4(subnet_, clientid_, hwaddr_, true,
+                                true, "host.example.com.", lease, 
                                 callout_handle, false);
     // Check that he got that single lease
     ASSERT_TRUE(lease);
@@ -1406,7 +1486,9 @@ TEST_F(HookAllocEngine4Test, lease4_select) {
 
     Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
                                                IOAddress("0.0.0.0"),
-                                               false, callout_handle);
+                                               false, false, "",
+                                               false, callout_handle,
+                                               old_lease_);
     // Check that we got a lease
     ASSERT_TRUE(lease);
 
@@ -1468,8 +1550,11 @@ TEST_F(HookAllocEngine4Test, change_lease4_select) {
     CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
 
     // Call allocateAddress4. Callouts should be triggered here.
-    Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
-                                               false, callout_handle);
+    Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
+                                               IOAddress("0.0.0.0"),
+                                               false, false, "",
+                                               false, callout_handle,
+                                               old_lease_);
     // Check that we got a lease
     ASSERT_TRUE(lease);
 

+ 69 - 2
src/lib/dhcpsrv/tests/lease_mgr_unittest.cc

@@ -245,7 +245,7 @@ TEST(LeaseMgr, getParameter) {
 ///
 /// Lease4 is also defined in lease_mgr.h, so is tested in this file as well.
 // This test checks if the Lease4 structure can be instantiated correctly
-TEST(Lease4, Lease4Constructor) {
+TEST(Lease4, constructor) {
 
     // Random values for the tests
     const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
@@ -292,12 +292,79 @@ TEST(Lease4, Lease4Constructor) {
     }
 }
 
+// This test verfies that copy constructor copies Lease4 fields correctly.
+TEST(Lease4, copyConstructor) {
+
+    // Random values for the tests
+    const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
+    std::vector<uint8_t> hwaddr(HWADDR, HWADDR + sizeof(HWADDR));
+
+    const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
+    std::vector<uint8_t> clientid_vec(CLIENTID, CLIENTID + sizeof(CLIENTID));
+    ClientId clientid(clientid_vec);
+
+    // ...and a time
+    const time_t current_time = time(NULL);
+
+    // Other random constants.
+    const uint32_t SUBNET_ID = 42;
+    const uint32_t VALID_LIFETIME = 500;
+
+    // Create the lease
+    Lease4 lease(0xffffffff, HWADDR, sizeof(HWADDR),
+                 CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, 0, 0, current_time,
+                 SUBNET_ID);
+
+    // Use copy constructor to copy the lease.
+    Lease4 copied_lease(lease);
+
+    // Both leases should be now equal. When doing this check we assume that
+    // the equality operator works correctly.
+    EXPECT_TRUE(lease == copied_lease);
+    // Client IDs are equal, but they should be in two distinct pointers.
+    EXPECT_FALSE(lease.client_id_ == copied_lease.client_id_);
+}
+
+// This test verfies that the assignment operator copies all Lease4 fields
+// correctly.
+TEST(Lease4, operatorAssign) {
+
+    // Random values for the tests
+    const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
+    std::vector<uint8_t> hwaddr(HWADDR, HWADDR + sizeof(HWADDR));
+
+    const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
+    std::vector<uint8_t> clientid_vec(CLIENTID, CLIENTID + sizeof(CLIENTID));
+    ClientId clientid(clientid_vec);
+
+    // ...and a time
+    const time_t current_time = time(NULL);
+
+    // Other random constants.
+    const uint32_t SUBNET_ID = 42;
+    const uint32_t VALID_LIFETIME = 500;
+
+    // Create the lease
+    Lease4 lease(0xffffffff, HWADDR, sizeof(HWADDR),
+                 CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, 0, 0, current_time,
+                 SUBNET_ID);
+
+    // Use assignment operator to assign the lease.
+    Lease4 copied_lease = lease;
+
+    // Both leases should be now equal. When doing this check we assume that
+    // the equality operator works correctly.
+    EXPECT_TRUE(lease == copied_lease);
+    // Client IDs are equal, but they should be in two distinct pointers.
+    EXPECT_FALSE(lease.client_id_ == copied_lease.client_id_);
+}
+
 /// @brief Lease4 Equality Test
 ///
 /// Checks that the operator==() correctly compares two leases for equality.
 /// As operator!=() is also defined for this class, every check on operator==()
 /// is followed by the reverse check on operator!=().
-TEST(Lease4, OperatorEquals) {
+TEST(Lease4, operatorEquals) {
 
     // Random values for the tests
     const uint32_t ADDRESS = 0x01020304;

+ 6 - 0
src/lib/dhcpsrv/tests/test_utils.cc

@@ -47,6 +47,9 @@ detailCompareLease(const Lease4Ptr& first, const Lease4Ptr& second) {
     EXPECT_EQ(first->valid_lft_, second->valid_lft_);
     EXPECT_EQ(first->cltt_, second->cltt_);
     EXPECT_EQ(first->subnet_id_, second->subnet_id_);
+    EXPECT_EQ(first->fqdn_fwd_, second->fqdn_fwd_);
+    EXPECT_EQ(first->fqdn_rev_, second->fqdn_rev_);
+    EXPECT_EQ(first->hostname_, second->hostname_);
 }
 
 void
@@ -67,6 +70,9 @@ detailCompareLease(const Lease6Ptr& first, const Lease6Ptr& second) {
     EXPECT_EQ(first->valid_lft_, second->valid_lft_);
     EXPECT_EQ(first->cltt_, second->cltt_);
     EXPECT_EQ(first->subnet_id_, second->subnet_id_);
+    EXPECT_EQ(first->fqdn_fwd_, second->fqdn_fwd_);
+    EXPECT_EQ(first->fqdn_rev_, second->fqdn_rev_);
+    EXPECT_EQ(first->hostname_, second->hostname_);
 }
 
 };