Browse Source

[4302] Refactored host data source classes.

The updated API exposes functions which retrieve hosts
by any identifier and identifier type, rather than DUID
or HW address.
Marcin Siodelski 9 years ago
parent
commit
f551e0e480

+ 50 - 1
src/lib/dhcpsrv/base_host_data_source.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -98,6 +98,23 @@ public:
     virtual ConstHostCollection
     getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr()) const = 0;
 
+    /// @brief Return all hosts connected to any subnet for which reservations
+    /// have been made using a specified identifier.
+    ///
+    /// This method returns all @c Host objects which represent reservations
+    /// for a specified identifier. This method may return multiple hosts
+    /// because a particular client may have reservations in multiple subnets.
+    ///
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Collection of const @c Host objects.
+    virtual ConstHostCollection
+    getAll(const Host::IdentifierType& identifier_type,
+           const uint8_t* identifier_begin,
+           const size_t identifier_len) const = 0;
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @c Host objects if they are connected
@@ -127,6 +144,23 @@ public:
     get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
          const DuidPtr& duid = DuidPtr()) const = 0;
 
+
+    /// @brief Returns a host connected to the IPv4 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Const @c Host object for which reservation has been made using
+    /// the specified identifier.
+    virtual ConstHostPtr
+    get4(const SubnetID& subnet_id,
+         const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin,
+         const size_t identifier_len) const = 0;
+
     /// @brief Returns a host connected to the IPv4 subnet and having
     /// a reservation for a specified IPv4 address.
     ///
@@ -165,6 +199,21 @@ public:
     get6(const SubnetID& subnet_id, const DuidPtr& duid,
          const HWAddrPtr& hwaddr = HWAddrPtr()) const = 0;
 
+    /// @brief Returns a host connected to the IPv6 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Const @c Host object for which reservation has been made using
+    /// the specified identifier.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id,
+         const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin,
+         const size_t identifier_len) const = 0;
 
     /// @brief Returns a host using the specified IPv6 prefix.
     ///

+ 150 - 38
src/lib/dhcpsrv/cfg_hosts.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -34,6 +34,29 @@ CfgHosts::getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid) {
 }
 
 ConstHostCollection
+CfgHosts::getAll(const Host::IdentifierType& identifier_type,
+                 const uint8_t* identifier_begin,
+                 const size_t identifier_len) const {
+    // Do not issue logging message here because it will be logged by
+    // the getAllInternal method.
+    ConstHostCollection collection;
+    getAllInternal<ConstHostCollection>(identifier_type, identifier_begin,
+                                        identifier_len, collection);
+    return (collection);
+}
+
+HostCollection
+CfgHosts::getAll(const Host::IdentifierType& identifier_type,
+                 const uint8_t* identifier_begin, const size_t identifier_len) {
+    // Do not issue logging message here because it will be logged by
+    // the getAllInternal method.
+    HostCollection collection;
+    getAllInternal<HostCollection>(identifier_type, identifier_begin,
+                                   identifier_len, collection);
+    return (collection);
+}
+
+ConstHostCollection
 CfgHosts::getAll4(const IOAddress& address) const {
     // Do not issue logging message here because it will be logged by
     // the getAllInternal4 method.
@@ -71,27 +94,26 @@ CfgHosts::getAll6(const IOAddress& address) {
 
 template<typename Storage>
 void
-CfgHosts::getAllInternal(const std::vector<uint8_t>& identifier,
-                         const Host::IdentifierType& identifier_type,
+CfgHosts::getAllInternal(const Host::IdentifierType& identifier_type,
+                         const uint8_t* identifier,
+                         const size_t identifier_len,
                          Storage& storage) const {
     // We will need to transform the identifier into the textual format.
     // Until we do it, we mark it as invalid.
     std::string identifier_text = "(invalid)";
-    if (!identifier.empty()) {
-        try {
-            // Use Host object to find the textual form of the identifier.
-            // This may throw exception if the identifier is invalid.
-            Host host(&identifier[0], identifier.size(), identifier_type,
-                      SubnetID(0), SubnetID(0), IOAddress::IPV4_ZERO_ADDRESS());
-            identifier_text = host.getIdentifierAsText();
-
-        } catch (...) {
-            // Suppress exception and keep using (invalid) as an
-            // identifier. We will log that the identifier is
-            // invalid and return.
-        }
-
+    try {
+        // Use Host object to find the textual form of the identifier.
+        // This may throw exception if the identifier is invalid.
+        Host host(identifier, identifier_len, identifier_type,
+                  SubnetID(0), SubnetID(0), IOAddress::IPV4_ZERO_ADDRESS());
+        identifier_text = host.getIdentifierAsText();
+
+    } catch (...) {
+        // Suppress exception and keep using (invalid) as an
+        // identifier. We will log that the identifier is
+        // invalid and return.
     }
+
     // This will log that we're invoking this function with the specified
     // identifier. The identifier may also be marked as (invalid) if it
     // had 0 length or its type is unsupported.
@@ -106,10 +128,13 @@ CfgHosts::getAllInternal(const std::vector<uint8_t>& identifier,
     // Use the identifier and identifier type as a composite key.
     const HostContainerIndex0& idx = hosts_.get<0>();
     boost::tuple<const std::vector<uint8_t>, const Host::IdentifierType> t =
-        boost::make_tuple(identifier, identifier_type);
+        boost::make_tuple(std::vector<uint8_t>(identifier,
+                                               identifier + identifier_len),
+                                               identifier_type);
 
     // Append each Host object to the storage.
-    for (HostContainerIndex0::iterator host = idx.lower_bound(t); host != idx.upper_bound(t);
+    for (HostContainerIndex0::iterator host = idx.lower_bound(t);
+         host != idx.upper_bound(t);
          ++host) {
         LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE_DETAIL_DATA,
                   HOSTS_CFG_GET_ALL_IDENTIFIER_HOST)
@@ -133,12 +158,14 @@ CfgHosts::getAllInternal(const HWAddrPtr& hwaddr, const DuidPtr& duid,
         .arg(duid ? duid->toText() : "(no-duid)");
 
     // Get hosts using HW address.
-    if (hwaddr) {
-        getAllInternal<Storage>(hwaddr->hwaddr_, Host::IDENT_HWADDR, storage);
+    if (hwaddr && !hwaddr->hwaddr_.empty()) {
+        getAllInternal<Storage>(Host::IDENT_HWADDR, &hwaddr->hwaddr_[0],
+                                hwaddr->hwaddr_.size(), storage);
     }
     // Get hosts using DUID.
-    if (duid) {
-        getAllInternal<Storage>(duid->getDuid(), Host::IDENT_DUID, storage);
+    if (duid && !duid->getDuid().empty()) {
+        getAllInternal<Storage>(Host::IDENT_DUID, &duid->getDuid()[0],
+                                duid->getDuid().size(), storage);
     }
 }
 
@@ -206,7 +233,18 @@ CfgHosts::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
                const DuidPtr& duid) const {
     // Do not log here because getHostInternal logs.
     // The false value indicates that it is an IPv4 subnet.
-    return (getHostInternal(subnet_id, false, hwaddr, duid));
+    HostPtr host;
+    if (hwaddr && !hwaddr->hwaddr_.empty()) {
+        host = getHostInternal(subnet_id, false, Host::IDENT_HWADDR,
+                               &hwaddr->hwaddr_[0],
+                               hwaddr->hwaddr_.size());
+    }
+    if (!host && duid && !duid->getDuid().empty()) {
+        host = getHostInternal(subnet_id, false, Host::IDENT_DUID,
+                               &duid->getDuid()[0],
+                               duid->getDuid().size());
+    }
+    return (host);
 }
 
 HostPtr
@@ -214,7 +252,36 @@ CfgHosts::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
                const DuidPtr& duid) {
     // Do not log here because getHostInternal logs.
     // The false value indicates that it is an IPv4 subnet.
-    return (getHostInternal(subnet_id, false, hwaddr, duid));
+    HostPtr host;
+    if (hwaddr && !hwaddr->hwaddr_.empty()) {
+        host = getHostInternal(subnet_id, false, Host::IDENT_HWADDR,
+                               &hwaddr->hwaddr_[0],
+                               hwaddr->hwaddr_.size());
+    }
+    if (!host && duid && !duid->getDuid().empty()) {
+        host = getHostInternal(subnet_id, false, Host::IDENT_DUID,
+                               &duid->getDuid()[0],
+                               duid->getDuid().size());
+    }
+    return (host);
+}
+
+ConstHostPtr
+CfgHosts::get4(const SubnetID& subnet_id,
+               const Host::IdentifierType& identifier_type,
+               const uint8_t* identifier_begin,
+               const size_t identifier_len) const {
+    return (getHostInternal(subnet_id, false, identifier_type, identifier_begin,
+                            identifier_len));
+}
+
+HostPtr
+CfgHosts::get4(const SubnetID& subnet_id,
+               const Host::IdentifierType& identifier_type,
+               const uint8_t* identifier_begin,
+               const size_t identifier_len) {
+    return (getHostInternal(subnet_id, false, identifier_type, identifier_begin,
+                            identifier_len));
 }
 
 ConstHostPtr
@@ -246,7 +313,19 @@ CfgHosts::get6(const SubnetID& subnet_id, const DuidPtr& duid,
                const HWAddrPtr& hwaddr) const {
     // Do not log here because getHostInternal logs.
     // The true value indicates that it is an IPv6 subnet.
-    return (getHostInternal(subnet_id, true, hwaddr, duid));
+    HostPtr host;
+    if (duid && !duid->getDuid().empty()) {
+        host = getHostInternal(subnet_id, true, Host::IDENT_DUID,
+                               &duid->getDuid()[0],
+                               duid->getDuid().size());
+    }
+    if (!host && hwaddr && !hwaddr->hwaddr_.empty()) {
+        host = getHostInternal(subnet_id, true, Host::IDENT_HWADDR,
+                               &hwaddr->hwaddr_[0],
+                               hwaddr->hwaddr_.size());
+    }
+
+    return (host);
 }
 
 HostPtr
@@ -254,7 +333,37 @@ CfgHosts::get6(const SubnetID& subnet_id, const DuidPtr& duid,
                const HWAddrPtr& hwaddr) {
     // Do not log here because getHostInternal logs.
     // The true value indicates that it is an IPv6 subnet.
-    return (getHostInternal(subnet_id, true, hwaddr, duid));
+    HostPtr host;
+    if (duid && !duid->getDuid().empty()) {
+        host = getHostInternal(subnet_id, true, Host::IDENT_DUID,
+                               &duid->getDuid()[0],
+                               duid->getDuid().size());
+    }
+    if (!host && hwaddr && !hwaddr->hwaddr_.empty()) {
+        host = getHostInternal(subnet_id, true, Host::IDENT_HWADDR,
+                               &hwaddr->hwaddr_[0],
+                               hwaddr->hwaddr_.size());
+    }
+
+    return (host);
+}
+
+ConstHostPtr
+CfgHosts::get6(const SubnetID& subnet_id,
+               const Host::IdentifierType& identifier_type,
+               const uint8_t* identifier_begin,
+               const size_t identifier_len) const {
+    return (getHostInternal(subnet_id, true, identifier_type, identifier_begin,
+                            identifier_len));
+}
+
+HostPtr
+CfgHosts::get6(const SubnetID& subnet_id,
+               const Host::IdentifierType& identifier_type,
+               const uint8_t* identifier_begin,
+               const size_t identifier_len) {
+    return (getHostInternal(subnet_id, true, identifier_type, identifier_begin,
+                            identifier_len));
 }
 
 ConstHostPtr
@@ -357,18 +466,22 @@ CfgHosts::getAllInternal6(const SubnetID& subnet_id,
 
 HostPtr
 CfgHosts::getHostInternal(const SubnetID& subnet_id, const bool subnet6,
-                          const HWAddrPtr& hwaddr, const DuidPtr& duid) const {
-    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_GET_ONE_SUBNET_ID_HWADDR_DUID)
+                          const Host::IdentifierType& identifier_type,
+                          const uint8_t* identifier,
+                          const size_t identifier_len) const {
+
+/*    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_GET_ONE_SUBNET_ID_HWADDR_DUID)
         .arg(subnet6 ? "IPv6" : "IPv4")
         .arg(subnet_id)
         .arg(hwaddr ? hwaddr->toText() : "(no-hwaddr)")
-        .arg(duid ? duid->toText() : "(no-duid)");
+        .arg(duid ? duid->toText() : "(no-duid)"); */
 
-    // Get all hosts for the HW address and DUID. This may return multiple hosts
+    // Get all hosts for a specified identifier. This may return multiple hosts
     // for different subnets, but the number of hosts returned should be low
     // because one host presumably doesn't show up in many subnets.
     HostCollection hosts;
-    getAllInternal<HostCollection>(hwaddr, duid, hosts);
+    getAllInternal<HostCollection>(identifier_type, identifier, identifier_len,
+                                   hosts);
 
     HostPtr host;
     // Iterate over the returned hosts and select those for which the
@@ -394,15 +507,15 @@ CfgHosts::getHostInternal(const SubnetID& subnet_id, const bool subnet6,
                 isc_throw(DuplicateHost,  "more than one reservation found"
                           " for the host belonging to the subnet with id '"
                           << subnet_id << "' and using the HW address '"
-                          << (hwaddr ? hwaddr->toText(false) : "(null)")
-                          << "' and DUID '"
-                          << (duid ? duid->toText() : "(null)")
+//                          << (hwaddr ? hwaddr->toText(false) : "(null)")
+//                          << "' and DUID '"
+//                          << (duid ? duid->toText() : "(null)")
                           << "'");
             }
         }
     }
 
-    if (host) {
+/*    if (host) {
         LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
                   HOSTS_CFG_GET_ONE_SUBNET_ID_HWADDR_DUID)
             .arg(subnet_id)
@@ -416,12 +529,11 @@ CfgHosts::getHostInternal(const SubnetID& subnet_id, const bool subnet6,
             .arg(subnet_id)
             .arg(hwaddr ? hwaddr->toText() : "(no-hwaddr)")
             .arg(duid ? duid->toText() : "(no-duid)");
-    }
+    } */
 
     return (host);
 }
 
-
 void
 CfgHosts::add(const HostPtr& host) {
     LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_ADD_HOST)

+ 106 - 14
src/lib/dhcpsrv/cfg_hosts.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -69,6 +69,38 @@ public:
     virtual HostCollection
     getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr());
 
+    /// @brief Return all hosts connected to any subnet for which reservations
+    /// have been made using a specified identifier.
+    ///
+    /// This method returns all @c Host objects which represent reservations
+    /// for a specified identifier. This method may return multiple hosts
+    /// because a particular client may have reservations in multiple subnets.
+    ///
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Collection of const @c Host objects.
+    virtual ConstHostCollection
+    getAll(const Host::IdentifierType& identifier_type,
+           const uint8_t* identifier_begin, const size_t identifier_len) const;
+
+    /// @brief Non-const version of the @c getAll const method.
+    ///
+    /// This method returns all @c Host objects which represent reservations
+    /// for a specified identifier. This method may return multiple hosts
+    /// because a particular client may have reservations in multiple subnets.
+    ///
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Collection of non-const @c Host objects.
+    virtual HostCollection
+    getAll(const Host::IdentifierType& identifier_type,
+           const uint8_t* identifier_begin,
+           const size_t identifier_len);
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @c Host objects if they are connected
@@ -143,6 +175,34 @@ public:
     get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
          const DuidPtr& duid = DuidPtr());
 
+    /// @brief Returns a host connected to the IPv4 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Const @c Host object for which reservation has been made using
+    /// the specified identifier.
+    virtual ConstHostPtr
+    get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len) const;
+
+    /// @brief Returns a host connected to the IPv4 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Non-const @c Host object for which reservation has been made
+    /// using the specified identifier.
+    virtual HostPtr
+    get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len);
+
     /// @brief Returns a host connected to the IPv4 subnet and having
     /// a reservation for a specified IPv4 address.
     ///
@@ -183,6 +243,34 @@ public:
     get6(const SubnetID& subnet_id, const DuidPtr& duid,
          const HWAddrPtr& hwaddr = HWAddrPtr());
 
+    /// @brief Returns a host connected to the IPv6 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Const @c Host object for which reservation has been made using
+    /// the specified identifier.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len) const;
+
+    /// @brief Returns a host connected to the IPv6 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Non-const @c Host object for which reservation has been made
+    /// using the specified identifier.
+    virtual HostPtr
+    get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len);
+
     /// @brief Returns a host using the specified IPv6 prefix.
     ///
     /// @param prefix IPv6 prefix for which the @c Host object is searched.
@@ -243,18 +331,19 @@ private:
     /// @brief Returns @c Host objects for the specific identifier and type.
     ///
     /// This private method is called by the @c CfgHosts::getAllInternal
-    /// method which finds the @c Host objects using HW address or DUID.
+    /// method which finds the @c Host objects using specified identifier.
     /// The retrieved objects are appended to the @c storage container.
     ///
-    /// @param identifier Binary representation of the HW addres or DUID (or
-    /// other future identifier).
     /// @param identifier_type The type of the supplied identifier.
+    /// @param identifier Pointer to a first byte of the identifier.
+    /// @param identifier_len Length of the identifier.
     /// @param [out] storage Container to which the retreived objects are
     /// appended.
     /// @tparam One of the @c ConstHostCollection of @c HostCollection.
     template<typename Storage>
-    void getAllInternal(const std::vector<uint8_t>& identifier,
-                        const Host::IdentifierType& identifier_type,
+    void getAllInternal(const Host::IdentifierType& identifier_type,
+                        const uint8_t* identifier,
+                        const size_t identifier_len,
                         Storage& storage) const;
 
     /// @brief Returns @c Host objects for the specified HW address or DUID.
@@ -323,22 +412,25 @@ private:
 
     /// @brief Returns @c Host object connected to a subnet.
     ///
-    /// This private method returns a pointer to the @c Host object identified
-    /// by the HW address or DUID and connected to an IPv4 or IPv6 subnet.
+    /// This private method returns a pointer to the @c Host object using
+    /// a specified identifier and connected to an IPv4 or IPv6 subnet.
     ///
     /// @param subnet_id IPv4 or IPv6 subnet identifier.
     /// @param subnet6 A boolean flag which indicates if the subnet identifier
     /// points to a IPv4 (if false) or IPv6 subnet (if true).
-    /// @param hwaddr HW address identifying a host.
-    /// @param duid DUID identifying a host.
+    /// @param identifier_type Indentifier type.
+    /// @param identifier Pointer to a first byte of the buffer holding an
+    /// identifier.
+    /// @param identifier_len Identifier length.
     ///
     /// @return Pointer to the found host, or NULL if no host found.
     /// @throw isc::dhcp::DuplicateHost if method found more than one matching
     /// @c Host object.
-    HostPtr getHostInternal(const SubnetID& subnet_id,
-                            const bool subnet6,
-                            const HWAddrPtr& hwaddr,
-                            const DuidPtr& duid) const;
+    HostPtr
+    getHostInternal(const SubnetID& subnet_id, const bool subnet6,
+                    const Host::IdentifierType& identifier_type,
+                    const uint8_t* identifier,
+                    const size_t identifier_len) const;
 
     /// @brief Returns the @c Host object holding reservation for the IPv6
     /// address and connected to the specific subnet.

+ 46 - 1
src/lib/dhcpsrv/host_mgr.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -77,6 +77,23 @@ HostMgr::getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid) const {
 }
 
 ConstHostCollection
+HostMgr::getAll(const Host::IdentifierType& identifier_type,
+                const uint8_t* identifier_begin,
+                const size_t identifier_len) const {
+    ConstHostCollection hosts = getCfgHosts()->getAll(identifier_type,
+                                                      identifier_begin,
+                                                      identifier_len);
+    if (alternate_source_) {
+        ConstHostCollection hosts_plus =
+            alternate_source_->getAll(identifier_type, identifier_begin,
+                                      identifier_len);
+        hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
+    }
+    return (hosts);
+}
+
+
+ConstHostCollection
 HostMgr::getAll4(const IOAddress& address) const {
     ConstHostCollection hosts = getCfgHosts()->getAll4(address);
     if (alternate_source_) {
@@ -108,6 +125,20 @@ HostMgr::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
 
 ConstHostPtr
 HostMgr::get4(const SubnetID& subnet_id,
+              const Host::IdentifierType& identifier_type,
+              const uint8_t* identifier_begin,
+              const size_t identifier_len) const {
+    ConstHostPtr host = getCfgHosts()->get4(subnet_id, identifier_type,
+                                            identifier_begin, identifier_len);
+    if (!host && alternate_source_) {
+        host = alternate_source_->get4(subnet_id, identifier_type,
+                                       identifier_begin, identifier_len);
+    }
+    return (host);
+}
+
+ConstHostPtr
+HostMgr::get4(const SubnetID& subnet_id,
               const asiolink::IOAddress& address) const {
     ConstHostPtr host = getCfgHosts()->get4(subnet_id, address);
     if (!host && alternate_source_) {
@@ -156,6 +187,20 @@ HostMgr::get6(const IOAddress& prefix, const uint8_t prefix_len) const {
 
 ConstHostPtr
 HostMgr::get6(const SubnetID& subnet_id,
+              const Host::IdentifierType& identifier_type,
+              const uint8_t* identifier_begin,
+              const size_t identifier_len) const {
+    ConstHostPtr host = getCfgHosts()->get6(subnet_id, identifier_type,
+                                            identifier_begin, identifier_len);
+    if (!host && alternate_source_) {
+        host = alternate_source_->get6(subnet_id, identifier_type,
+                                       identifier_begin, identifier_len);
+    }
+    return (host);
+}
+
+ConstHostPtr
+HostMgr::get6(const SubnetID& subnet_id,
               const asiolink::IOAddress& addr) const {
     ConstHostPtr host = getCfgHosts()->get6(subnet_id, addr);
     if (!host && alternate_source_) {

+ 56 - 1
src/lib/dhcpsrv/host_mgr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -101,6 +101,27 @@ public:
     virtual ConstHostCollection
     getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr()) const;
 
+    /// @brief Return all hosts connected to any subnet for which reservations
+    /// have been made using a specified identifier.
+    ///
+    /// This method returns all @c Host objects representing reservations for
+    /// a specified identifier as documented in the
+    /// @c BaseHostDataSource::getAll.
+    ///
+    /// It retrieves reservations from both primary and alternate host data
+    /// source as a single collection of @c Host objects, i.e. if matching
+    /// reservations are in both sources, all of them are returned.
+    ///
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Collection of const @c Host objects.
+    virtual ConstHostCollection
+    getAll(const Host::IdentifierType& identifier_type,
+           const uint8_t* identifier_begin,
+           const size_t identifier_len) const;
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @c Host objects if they are connected to
@@ -131,6 +152,23 @@ public:
     get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
          const DuidPtr& duid = DuidPtr()) const;
 
+    /// @brief Returns a host connected to the IPv4 subnet.
+    ///
+    /// This method returns a single reservation for a particular host as
+    /// documneted in the @c BaseHostDataSource::get4.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Const @c Host object for which reservation has been made using
+    /// the specified identifier.
+    virtual ConstHostPtr
+    get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len) const;
+
     /// @brief Returns a host connected to the IPv4 subnet and having
     /// a reservation for a specified IPv4 address.
     ///
@@ -161,6 +199,23 @@ public:
     get6(const SubnetID& subnet_id, const DuidPtr& duid,
          const HWAddrPtr& hwaddr = HWAddrPtr()) const;
 
+    /// @brief Returns a host connected to the IPv6 subnet.
+    ///
+    /// This method returns a host connected to the IPv6 subnet as described
+    /// in the @c BaseHostDataSource::get6.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Const @c Host object for which reservation has been made using
+    /// the specified identifier.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len) const;
+
     /// @brief Returns a host using the specified IPv6 prefix.
     ///
     /// This method returns a host using specified IPv6 prefix, as described

+ 129 - 132
src/lib/dhcpsrv/mysql_host_data_source.cc

@@ -1117,6 +1117,29 @@ public:
                            boost::shared_ptr<MySqlHostExchange> exchange,
                            ConstHostCollection& result, bool single) const;
 
+    /// @brief Retrieves a host by subnet and client's unique identifier.
+    ///
+    /// This method is used by both MySqlHostDataSource::get4 and
+    /// MySqlHOstDataSource::get6 methods.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    /// @param stindex Statement index.
+    /// @param exchange Pointer to the exchange object used for the
+    /// particular query.
+    ///
+    /// @return Pointer to const instance of Host or null pointer if
+    /// no host found.
+    ConstHostPtr getHost(const SubnetID& subnet_id,
+                         const Host::IdentifierType& identifier_type,
+                         const uint8_t* identifier_begin,
+                         const size_t identifier_len,
+                         MySqlHostDataSource::StatementIndex stindex,
+                         boost::shared_ptr<MySqlHostExchange> exchange) const;
+
     /// @brief Pointer to the object representing an exchange which
     /// can be used to retrieve DHCPv4 reservation.
     boost::shared_ptr<MySqlHostExchange> host_exchange_;
@@ -1276,6 +1299,50 @@ getHostCollection(MySqlHostDataSource::StatementIndex stindex,
     }
 }
 
+ConstHostPtr
+MySqlHostDataSourceImpl::
+getHost(const SubnetID& subnet_id,
+        const Host::IdentifierType& identifier_type,
+        const uint8_t* identifier_begin,
+        const size_t identifier_len,
+        MySqlHostDataSource::StatementIndex stindex,
+        boost::shared_ptr<MySqlHostExchange> exchange) const {
+
+    // Set up the WHERE clause value
+    MYSQL_BIND inbind[3];
+    memset(inbind, 0, sizeof(inbind));
+
+    uint32_t subnet_buffer = static_cast<uint32_t>(subnet_id);
+    inbind[0].buffer_type = MYSQL_TYPE_LONG;
+    inbind[0].buffer = reinterpret_cast<char*>(&subnet_buffer);
+    inbind[0].is_unsigned = MLM_TRUE;
+
+    // Identifier value.
+    std::vector<char> identifier_vec(identifier_begin,
+                                     identifier_begin + identifier_len);
+    unsigned long length = identifier_vec.size();
+    inbind[2].buffer_type = MYSQL_TYPE_BLOB;
+    inbind[2].buffer = &identifier_vec[0];
+    inbind[2].buffer_length = length;
+    inbind[2].length = &length;
+
+    // Identifier type.
+    char identifier_type_copy = static_cast<char>(identifier_type);
+    inbind[1].buffer_type = MYSQL_TYPE_TINY;
+    inbind[1].buffer = reinterpret_cast<char*>(&identifier_type_copy);
+    inbind[1].is_unsigned = MLM_TRUE;
+
+    ConstHostCollection collection;
+    getHostCollection(stindex, inbind, exchange, collection, true);
+
+    // Return single record if present, else clear the host.
+    ConstHostPtr result;
+    if (!collection.empty())
+        result = *collection.begin();
+
+    return (result);
+}
+
 
 MySqlHostDataSource::
 MySqlHostDataSource(const MySqlConnection::ParameterMap& parameters)
@@ -1314,58 +1381,57 @@ MySqlHostDataSource::add(const HostPtr& host) {
 
         // Gets the last inserted hosts id
         uint64_t host_id = mysql_insert_id(impl_->conn_.mysql_);
-        for (IPv6ResrvIterator resv = v6resv.first; resv != v6resv.second; ++resv) {
+        for (IPv6ResrvIterator resv = v6resv.first; resv != v6resv.second;
+             ++resv) {
             impl_->addResv(resv->second, host_id);
         }
     }
 }
 
 ConstHostCollection
-MySqlHostDataSource::getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid) const {
-
-    // Set up the WHERE clause value
-    MYSQL_BIND inbind[2];
-    memset(inbind, 0, sizeof(inbind));
+MySqlHostDataSource::getAll(const HWAddrPtr& hwaddr,
+                            const DuidPtr& duid) const {
 
-    uint8_t dhcp_identifier_type = 0;
-    long unsigned int length = 0;
     if (duid){
-        // DUID
-        // set proper dhcp_identifier_type
-        dhcp_identifier_type = BaseHostDataSource::ID_DUID; // 1
-        inbind[1].buffer = reinterpret_cast<char*>(&dhcp_identifier_type);
-
-        const vector<uint8_t>& duid_vector = duid->getDuid();
-        length = duid_vector.size();
-        inbind[0].buffer_type = MYSQL_TYPE_BLOB;
-        inbind[0].buffer = reinterpret_cast<char*>
-            (const_cast<uint8_t*>(&duid_vector[0]));
-        inbind[0].buffer_length = length;
-        inbind[0].length = &length;
+        return (getAll(Host::IDENT_DUID, &duid->getDuid()[0],
+                       duid->getDuid().size()));
+
     } else if (hwaddr) {
-        // HW Address
-        dhcp_identifier_type = BaseHostDataSource::ID_HWADDR; // 0
-        inbind[1].buffer = reinterpret_cast<char*>(&dhcp_identifier_type);
-
-        const vector<uint8_t>& hwaddr_vector = hwaddr->hwaddr_;
-        length = hwaddr_vector.size();
-        inbind[0].buffer_type = MYSQL_TYPE_BLOB;
-        inbind[0].buffer = reinterpret_cast<char*>
-            (const_cast<uint8_t*>(&hwaddr_vector[0]));
-        inbind[0].buffer_length = length;
-        inbind[0].length = &length;
+        return (getAll(Host::IDENT_HWADDR,
+                       &hwaddr->hwaddr_[0],
+                       hwaddr->hwaddr_.size()));
     }
 
-    // dhcp identifier type
+    return (ConstHostCollection());
+}
+
+ConstHostCollection
+MySqlHostDataSource::getAll(const Host::IdentifierType& identifier_type,
+                            const uint8_t* identifier_begin,
+                            const size_t identifier_len) const {
+    // Set up the WHERE clause value
+    MYSQL_BIND inbind[2];
+    memset(inbind, 0, sizeof(inbind));
+
+    // Identifier type.
+    char identifier_type_copy = static_cast<char>(identifier_type);
+    inbind[1].buffer = &identifier_type_copy;
     inbind[1].buffer_type = MYSQL_TYPE_TINY;
-    inbind[1].buffer = reinterpret_cast<char*>(&dhcp_identifier_type);
     inbind[1].is_unsigned = MLM_TRUE;
 
+    // Identifier value.
+    std::vector<char> identifier_vec(identifier_begin,
+                                     identifier_begin + identifier_len);
+    unsigned long int length = identifier_vec.size();
+    inbind[0].buffer_type = MYSQL_TYPE_BLOB;
+    inbind[0].buffer = &identifier_vec[0];
+    inbind[0].buffer_length = length;
+    inbind[0].length = &length;
+
     ConstHostCollection result;
     impl_->getHostCollection(GET_HOST_HWADDR_DUID, inbind,
                              impl_->host_ipv6_exchange_,
                              result, false);
-
     return (result);
 }
 
@@ -1392,15 +1458,6 @@ ConstHostPtr
 MySqlHostDataSource::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
                           const DuidPtr& duid) const {
 
-    // Set up the WHERE clause value
-    MYSQL_BIND inbind[3];
-    memset(inbind, 0, sizeof(inbind));
-
-    uint32_t subnet_buffer = static_cast<uint32_t>(subnet_id);
-    inbind[0].buffer_type = MYSQL_TYPE_LONG;
-    inbind[0].buffer = reinterpret_cast<char*>(&subnet_buffer);
-    inbind[0].is_unsigned = MLM_TRUE;
-
     /// @todo: Rethink the logic in BaseHostDataSource::get4(subnet, hwaddr, duid)
     if (hwaddr && duid) {
         isc_throw(BadValue, "MySQL host data source get4() called with both"
@@ -1411,53 +1468,28 @@ MySqlHostDataSource::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
                   "neither hwaddr or duid specified, one of them is required");
     }
 
-    unsigned long length = 0;
-    uint8_t dhcp_identifier_type_ = 0;
-
     // Choosing one of the identifiers
     if (hwaddr) {
-        // set identifier type
-        dhcp_identifier_type_ = BaseHostDataSource::ID_HWADDR; // 0
-
-        // set identifier value
-        const vector<uint8_t>& hwaddr_vector = hwaddr->hwaddr_;
-        length = hwaddr_vector.size();
-        inbind[2].buffer_type = MYSQL_TYPE_BLOB;
-        inbind[2].buffer = reinterpret_cast<char*>
-            (const_cast<uint8_t*>(&hwaddr_vector[0]));
-        inbind[2].buffer_length = length;
-        inbind[2].length = &length;
+        return (get4(subnet_id, Host::IDENT_HWADDR, &hwaddr->hwaddr_[0],
+                     hwaddr->hwaddr_.size()));
 
     } else if (duid) {
-        // set identifier type
-        dhcp_identifier_type_ = BaseHostDataSource::ID_DUID; // 1
-
-        // set identifier value
-        const vector<uint8_t>& duid_vector = duid->getDuid();
-        length = duid_vector.size();
-        inbind[2].buffer_type = MYSQL_TYPE_BLOB;
-        inbind[2].buffer = reinterpret_cast<char*>
-            (const_cast<uint8_t*>(&duid_vector[0]));
-        inbind[2].buffer_length = length;
-        inbind[2].length = &length;
+        return (get4(subnet_id, Host::IDENT_DUID, &duid->getDuid()[0],
+                     duid->getDuid().size()));
     }
 
-    // dhcp identifier type
-    inbind[1].buffer_type = MYSQL_TYPE_TINY;
-    inbind[1].buffer = reinterpret_cast<char*>(&dhcp_identifier_type_);
-    inbind[1].is_unsigned = MLM_TRUE;
-
-    ConstHostCollection collection;
-    impl_->getHostCollection(GET_HOST_SUBID4_DHCPID, inbind,
-                             impl_->host_exchange_, collection,
-                             true);
+    return (ConstHostPtr());
+}
 
-    // Return single record if present, else clear the host.
-    ConstHostPtr result;
-    if (!collection.empty())
-        result = *collection.begin();
+ConstHostPtr
+MySqlHostDataSource::get4(const SubnetID& subnet_id,
+                          const Host::IdentifierType& identifier_type,
+                          const uint8_t* identifier_begin,
+                          const size_t identifier_len) const {
 
-    return (result);
+    return (impl_->getHost(subnet_id, identifier_type, identifier_begin,
+                   identifier_len, GET_HOST_SUBID4_DHCPID,
+                   impl_->host_exchange_));
 }
 
 ConstHostPtr
@@ -1493,15 +1525,6 @@ ConstHostPtr
 MySqlHostDataSource::get6(const SubnetID& subnet_id, const DuidPtr& duid,
                           const HWAddrPtr& hwaddr) const {
 
-    // Set up the WHERE clause value
-    MYSQL_BIND inbind[3];
-    memset(inbind, 0, sizeof(inbind));
-
-    uint32_t subnet_buffer = static_cast<uint32_t>(subnet_id);
-    inbind[0].buffer_type = MYSQL_TYPE_LONG;
-    inbind[0].buffer = reinterpret_cast<char*>(&subnet_buffer);
-    inbind[0].is_unsigned = MLM_TRUE;
-
     /// @todo: Rethink the logic in BaseHostDataSource::get6(subnet, hwaddr, duid)
     if (hwaddr && duid) {
         isc_throw(BadValue, "MySQL host data source get6() called with both"
@@ -1512,53 +1535,27 @@ MySqlHostDataSource::get6(const SubnetID& subnet_id, const DuidPtr& duid,
                   "neither hwaddr or duid specified, one of them is required");
     }
 
-    unsigned long length = 0;
-    uint8_t dhcp_identifier_type_ = 0;
-
     // Choosing one of the identifiers
     if (hwaddr) {
-        // set identifier type
-        dhcp_identifier_type_ = BaseHostDataSource::ID_HWADDR; // 0
-
-        // set identifier value
-        const vector<uint8_t>& hwaddr_vector = hwaddr->hwaddr_;
-        length = hwaddr_vector.size();
-        inbind[2].buffer_type = MYSQL_TYPE_BLOB;
-        inbind[2].buffer = reinterpret_cast<char*>
-            (const_cast<uint8_t*>(&hwaddr_vector[0]));
-        inbind[2].buffer_length = length;
-        inbind[2].length = &length;
+        return (get6(subnet_id, Host::IDENT_HWADDR, &hwaddr->hwaddr_[0],
+                     hwaddr->hwaddr_.size()));
     } else if (duid) {
-        // set identifier type
-        dhcp_identifier_type_ = BaseHostDataSource::ID_DUID; // 1
-
-        // set identifier value
-        const vector<uint8_t>& duid_vector = duid->getDuid();
-        length = duid_vector.size();
-        inbind[2].buffer_type = MYSQL_TYPE_BLOB;
-        inbind[2].buffer = reinterpret_cast<char*>
-            (const_cast<uint8_t*>(&duid_vector[0]));
-        inbind[2].buffer_length = length;
-        inbind[2].length = &length;
+        return (get6(subnet_id, Host::IDENT_DUID, &duid->getDuid()[0],
+                     duid->getDuid().size()));
     }
 
-    // dhcp identifier type
-    inbind[1].buffer_type = MYSQL_TYPE_TINY;
-    inbind[1].buffer = reinterpret_cast<char*>(&dhcp_identifier_type_);
-    inbind[1].is_unsigned = MLM_TRUE;
-
-    ConstHostCollection collection;
-    impl_->getHostCollection(GET_HOST_SUBID6_DHCPID, inbind,
-                             impl_->host_ipv6_exchange_,
-                             collection, true);
-
-    // Return single record if present, else clear the host.
-    ConstHostPtr result;
-    if (!collection.empty()) {
-        result = *collection.begin();
-    }
+    return (ConstHostPtr());
+}
 
-    return (result);
+ConstHostPtr
+MySqlHostDataSource::get6(const SubnetID& subnet_id,
+                          const Host::IdentifierType& identifier_type,
+                          const uint8_t* identifier_begin,
+                          const size_t identifier_len) const {
+
+    return (impl_->getHost(subnet_id, identifier_type, identifier_begin,
+                   identifier_len, GET_HOST_SUBID6_DHCPID,
+                   impl_->host_ipv6_exchange_));
 }
 
 ConstHostPtr

+ 44 - 0
src/lib/dhcpsrv/mysql_host_data_source.h

@@ -77,6 +77,22 @@ public:
     virtual ConstHostCollection
     getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr()) const;
 
+    /// @brief Return all hosts connected to any subnet for which reservations
+    /// have been made using a specified identifier.
+    ///
+    /// This method returns all @c Host objects which represent reservations
+    /// for a specified identifier. This method may return multiple hosts
+    /// because a particular client may have reservations in multiple subnets.
+    ///
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Collection of const @c Host objects.
+    virtual ConstHostCollection
+    getAll(const Host::IdentifierType& identifier_type,
+           const uint8_t* identifier_begin, const size_t identifier_len) const;
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @c Host objects if they are connected
@@ -106,6 +122,20 @@ public:
     get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
          const DuidPtr& duid = DuidPtr()) const;
 
+    /// @brief Returns a host connected to the IPv4 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Const @c Host object for which reservation has been made using
+    /// the specified identifier.
+    virtual ConstHostPtr
+    get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len) const;
+
     /// @brief Returns a host connected to the IPv4 subnet and having
     /// a reservation for a specified IPv4 address.
     ///
@@ -143,6 +173,20 @@ public:
     get6(const SubnetID& subnet_id, const DuidPtr& duid,
             const HWAddrPtr& hwaddr = HWAddrPtr()) const;
 
+    /// @brief Returns a host connected to the IPv6 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Const @c Host object for which reservation has been made using
+    /// the specified identifier.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len) const;
+
     /// @brief Returns a host using the specified IPv6 prefix.
     ///
     /// @param prefix IPv6 prefix for which the @c Host object is searched.

+ 40 - 47
src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -117,17 +117,19 @@ TEST_F(CfgHostsTest, getAllNonRepeatingHosts) {
     // Try to retrieve each added reservation using HW address and DUID. Do it
     // in the reverse order to make sure that the order doesn't matter.
     for (int i = 24; i >= 0; --i) {
-        // Get host identified by HW address. The DUID is non-zero but it
-        // points to a host for which the reservation hasn't been added.
-        HostCollection hosts = cfg.getAll(hwaddrs_[i], duids_[i + 25]);
+        // Get host identified by HW address.
+        HostCollection hosts = cfg.getAll(Host::IDENT_HWADDR,
+                                          &hwaddrs_[i]->hwaddr_[0],
+                                          hwaddrs_[i]->hwaddr_.size());
         ASSERT_EQ(1, hosts.size());
         EXPECT_EQ(i % 10 + 1, hosts[0]->getIPv4SubnetID());
         EXPECT_EQ(addressesa_[i].toText(),
                   hosts[0]->getIPv4Reservation().toText());
 
-        // Get host identified by DUID. The HW address is non-null but it
-        // points to a host for which the reservation hasn't been added.
-        hosts = cfg.getAll(hwaddrs_[i + 25], duids_[i]);
+        // Get host identified by DUID.
+        hosts = cfg.getAll(Host::IDENT_DUID,
+                           &duids_[i]->getDuid()[0],
+                           duids_[i]->getDuid().size());
         ASSERT_EQ(1, hosts.size());
         EXPECT_EQ(i % 5 + 1, hosts[0]->getIPv4SubnetID());
         EXPECT_EQ(addressesb_[i].toText(),
@@ -137,8 +139,10 @@ TEST_F(CfgHostsTest, getAllNonRepeatingHosts) {
     // Make sure that the reservations do not exist for the hardware addresses
     // and DUIDs from the range of 25 to 49.
     for (int i = 49; i >= 25; --i) {
-        EXPECT_TRUE(cfg.getAll(hwaddrs_[i]).empty());
-        EXPECT_TRUE(cfg.getAll(HWAddrPtr(), duids_[i]).empty());
+        EXPECT_TRUE(cfg.getAll(Host::IDENT_HWADDR, &hwaddrs_[i]->hwaddr_[0],
+                               hwaddrs_[i]->hwaddr_.size()).empty());
+        EXPECT_TRUE(cfg.getAll(Host::IDENT_DUID, &duids_[i]->getDuid()[0],
+                               duids_[i]->getDuid().size()).empty());
     }
 }
 
@@ -244,31 +248,24 @@ TEST_F(CfgHostsTest, get4) {
     }
 
     for (unsigned i = 0; i < 25; ++i) {
-        // Retrieve host by HW address. The DUID is non-null but there is no
-        // reservation made for the DUID so the reservation is returned for
-        // HW address.
-        HostPtr host = cfg.get4(SubnetID(1 + i % 2), hwaddrs_[i],
-                                duids_[i + 25]);
+        // Retrieve host by HW address.
+        HostPtr host = cfg.get4(SubnetID(1 + i % 2), Host::IDENT_HWADDR,
+                                &hwaddrs_[i]->hwaddr_[0],
+                                hwaddrs_[i]->hwaddr_.size());
         ASSERT_TRUE(host);
         EXPECT_EQ(1 + i % 2, host->getIPv4SubnetID());
         EXPECT_EQ(increase(IOAddress("192.0.2.5"), i),
                   host->getIPv4Reservation());
 
-        // Retrieve host by DUID. The HW address is non-null but there is no
-        // reservation made for the HW address so the reservation is returned
-        // for the DUID.
-        host = cfg.get4(SubnetID(1 + i % 2), hwaddrs_[i + 25], duids_[i]);
+        // Retrieve host by DUID.
+        host = cfg.get4(SubnetID(1 + i % 2), Host::IDENT_DUID,
+                        &duids_[i]->getDuid()[0], duids_[i]->getDuid().size());
         ASSERT_TRUE(host);
         EXPECT_EQ(1 + i % 2, host->getIPv4SubnetID());
         EXPECT_EQ(increase(IOAddress("192.0.2.100"), i),
                   host->getIPv4Reservation());
 
     }
-
-    // Also check that when the get4 finds multiple Host objects that fulfil
-    // search criteria, it will throw an exception. Note that the reservation
-    // exist both for hwaddrs_[0] and duids_[0].
-    EXPECT_THROW(cfg.get4(SubnetID(1), hwaddrs_[0], duids_[0]), DuplicateHost);
 }
 
 // This test checks that the reservations can be retrieved for the particular
@@ -298,11 +295,10 @@ TEST_F(CfgHostsTest, get6) {
     }
 
     for (unsigned i = 0; i < 25; ++i) {
-        // Retrieve host by HW address. The DUID is non-null but there is no
-        // reservation made for the DUID so the reservation is returned for
-        // HW address.
-        HostPtr host = cfg.get6(SubnetID(1 + i % 2), duids_[i + 25],
-                                hwaddrs_[i]);
+        // Retrieve host by HW address.
+        HostPtr host = cfg.get6(SubnetID(1 + i % 2), Host::IDENT_HWADDR,
+                                &hwaddrs_[i]->hwaddr_[0],
+                                hwaddrs_[i]->hwaddr_.size());
         ASSERT_TRUE(host);
         EXPECT_EQ(1 + i % 2, host->getIPv6SubnetID());
         IPv6ResrvRange reservations =
@@ -311,10 +307,9 @@ TEST_F(CfgHostsTest, get6) {
         EXPECT_EQ(increase(IOAddress("2001:db8:1::1"), i),
                   reservations.first->second.getPrefix());
 
-        // Retrieve host by DUID. The HW address is non-null but there is no
-        // reservation made for the HW address so the reservation is returned
-        // for the DUID.
-        host = cfg.get6(SubnetID(1 + i % 2), duids_[i], hwaddrs_[i + 25]);
+        // Retrieve host by DUID.
+        host = cfg.get6(SubnetID(1 + i % 2), Host::IDENT_DUID,
+                        &duids_[i]->getDuid()[0], duids_[i]->getDuid().size());
         ASSERT_TRUE(host);
         EXPECT_EQ(1 + i % 2, host->getIPv6SubnetID());
         reservations = host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
@@ -322,11 +317,6 @@ TEST_F(CfgHostsTest, get6) {
         EXPECT_EQ(increase(IOAddress("2001:db8:2::1"), i),
                   reservations.first->second.getPrefix());
     }
-
-    // Also check that when the get6 finds multiple Host objects that fulfil
-    // search criteria, it will throw an exception. Note that the reservation
-    // exist both for hwaddrs_[0] and duids_[0].
-    EXPECT_THROW(cfg.get6(SubnetID(1), duids_[0], hwaddrs_[0]), DuplicateHost);
 }
 
 // This test checks that the IPv6 reservations can be retrieved for a particular
@@ -376,30 +366,31 @@ TEST_F(CfgHostsTest, get6MultipleAddrs) {
 
         // Generate 5 unique addresses for this host.
         for (int j = 0; j < 5; ++j) {
-            std::stringstream tmp;
-            tmp << "2001:db8:" << i << "::" << j;
-            host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, tmp.str()));
+            std::stringstream address_stream;
+            address_stream << "2001:db8:" << i << "::" << j;
+            host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+                                           address_stream.str()));
         }
         cfg.add(host);
     }
 
-    // We don't care about HW/MAC addresses for now.
-    HWAddrPtr hwaddr_not_used;
-
     // Now check if we can retrieve each of those 25 hosts by using each
     // of their addresses.
     for (unsigned i = 0; i < 25; ++i) {
 
         // Check that the host is there.
-        HostPtr by_duid = cfg.get6(SubnetID(1 + i % 2), duids_[i], hwaddr_not_used);
+        HostPtr by_duid = cfg.get6(SubnetID(1 + i % 2), Host::IDENT_DUID,
+                                   &duids_[i]->getDuid()[0],
+                                   duids_[i]->getDuid().size());
         ASSERT_TRUE(by_duid);
 
         for (unsigned j = 0; j < 5; ++j) {
-            std::stringstream tmp;
-            tmp << "2001:db8:" << i << "::" << j;
+            std::stringstream address_stream;
+            address_stream << "2001:db8:" << i << "::" << j;
 
             // Retrieve host by (subnet-id,address).
-            HostPtr by_addr = cfg.get6(SubnetID(1 + i % 2), tmp.str());
+            HostPtr by_addr = cfg.get6(SubnetID(1 + i % 2),
+                                       address_stream.str());
             ASSERT_TRUE(by_addr);
 
             // The pointers should match. Maybe we should compare contents
@@ -462,6 +453,8 @@ TEST_F(CfgHostsTest, add6Invalid2Hosts) {
     EXPECT_THROW(cfg.add(host2), isc::dhcp::DuplicateHost);
 }
 
+// Check that error is reported when trying to add a host with subnet
+// ids equal to zero.
 TEST_F(CfgHostsTest, zeroSubnetIDs) {
     CfgHosts cfg;
     ASSERT_THROW(cfg.add(HostPtr(new Host(hwaddrs_[0]->toText(false),

+ 23 - 14
src/lib/dhcpsrv/tests/host_mgr_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -99,9 +99,13 @@ TEST_F(HostMgrTest, getAll) {
 
     // If there non-matching HW address is specified, nothing should be
     // returned.
-    ASSERT_TRUE(HostMgr::instance().getAll(hwaddrs_[1]).empty());
+    ASSERT_TRUE(HostMgr::instance().getAll(Host::IDENT_HWADDR,
+                                           &hwaddrs_[1]->hwaddr_[0],
+                                           hwaddrs_[1]->hwaddr_.size()).empty());
     // For the correct HW address, there should be two reservations.
-    hosts = HostMgr::instance().getAll(hwaddrs_[0]);
+    hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR,
+                                       &hwaddrs_[0]->hwaddr_[0],
+                                       hwaddrs_[0]->hwaddr_.size());
     ASSERT_EQ(2, hosts.size());
 
     // We don't know the order in which the reservations are returned so
@@ -137,9 +141,8 @@ TEST_F(HostMgrTest, getAll) {
 
 // This test verifies that it is possible to gather all reservations for the
 // specified IPv4 address from the HostMgr. The reservations are specified in
-// the server's configuration. Note: this test is currently disabled because the
-// getAll4 method is not implemented in the CfgHosts object.
-TEST_F(HostMgrTest, DISABLED_getAll4) {
+// the server's configuration.
+TEST_F(HostMgrTest, getAll4) {
     ConstHostCollection hosts =
         HostMgr::instance().getAll4(IOAddress("192.0.2.5"));
     ASSERT_TRUE(hosts.empty());
@@ -156,8 +159,12 @@ TEST_F(HostMgrTest, DISABLED_getAll4) {
     hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5"));
     ASSERT_EQ(2, hosts.size());
 
-    /// @todo Extend this test to sanity check the hosts, once the test
-    /// is enabled.
+    // Make sure that IPv4 address is correct.
+    EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
+    EXPECT_EQ("192.0.2.5", hosts[1]->getIPv4Reservation().toText());
+
+    // Make sure that two different hosts were returned.
+    EXPECT_NE(hosts[0]->getIPv4SubnetID(), hosts[1]->getIPv4SubnetID());
 }
 
 // This test verifies that it is possible to retrieve a reservation for the
@@ -173,7 +180,9 @@ TEST_F(HostMgrTest, get4) {
                                         IOAddress("192.0.2.5"))));
     CfgMgr::instance().commit();
 
-    host = HostMgr::instance().get4(SubnetID(1), hwaddrs_[0]);
+    host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR,
+                                    &hwaddrs_[0]->hwaddr_[0],
+                                    hwaddrs_[0]->hwaddr_.size());
     ASSERT_TRUE(host);
     EXPECT_EQ(1, host->getIPv4SubnetID());
     EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
@@ -193,17 +202,17 @@ TEST_F(HostMgrTest, get6) {
     getCfgHosts()->add(new_host);
     CfgMgr::instance().commit();
 
-    host = HostMgr::instance().get6(SubnetID(2), duids_[0]);
+    host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID,
+                                    &duids_[0]->getDuid()[0],
+                                    duids_[0]->getDuid().size());
     ASSERT_TRUE(host);
     EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
                                                IOAddress("2001:db8:1::1"))));
 }
 
 // This test verifies that it is possible to retrieve the reservation of the
-// particular IPv6 prefix using HostMgr. Note: this test is currently disabled
-// because the get6(prefix, prefix_len) method is not implemented in the
-// CfgHosts class.
-TEST_F(HostMgrTest, DISABLED_get6ByPrefix) {
+// particular IPv6 prefix using HostMgr.
+TEST_F(HostMgrTest, get6ByPrefix) {
     ConstHostPtr host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 64);
     ASSERT_FALSE(host);
 

+ 45 - 1
src/lib/dhcpsrv/writable_host_data_source.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -40,6 +40,22 @@ public:
     virtual HostCollection
     getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr()) = 0;
 
+    /// @brief Non-const version of the @c getAll const method.
+    ///
+    /// This method returns all @c Host objects which represent reservations
+    /// for a specified identifier. This method may return multiple hosts
+    /// because a particular client may have reservations in multiple subnets.
+    ///
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Collection of non-const @c Host objects.
+    virtual HostCollection
+    getAll(const Host::IdentifierType& identifier_type,
+           const uint8_t* identifier_begin,
+           const size_t identifier_len) = 0;
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @c Host objects if they are connected
@@ -69,6 +85,20 @@ public:
     get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
          const DuidPtr& duid = DuidPtr()) = 0;
 
+    /// @brief Returns a host connected to the IPv4 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Non-const @c Host object for which reservation has been made
+    /// using the specified identifier.
+    virtual HostPtr
+    get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len) = 0;
+
     /// @brief Returns a host connected to the IPv6 subnet.
     ///
     /// Implementations of this method should guard against the case when
@@ -87,6 +117,20 @@ public:
     get6(const SubnetID& subnet_id, const DuidPtr& duid,
          const HWAddrPtr& hwaddr = HWAddrPtr()) = 0;
 
+    /// @brief Returns a host connected to the IPv6 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a begining of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Non-const @c Host object for which reservation has been made
+    /// using the specified identifier.
+    virtual HostPtr
+    get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len) = 0;
+
     /// @brief Returns a host using the specified IPv6 prefix.
     ///
     /// @param prefix IPv6 prefix for which the @c Host object is searched.