Browse Source

[3563] HostContainer6 definitions added.

Tomek Mrugalski 10 years ago
parent
commit
8d9acab77f

+ 95 - 4
src/lib/dhcpsrv/cfg_hosts.cc

@@ -49,6 +49,20 @@ CfgHosts::getAll4(const IOAddress& address) {
     return (collection);
 }
 
+ConstHostCollection
+CfgHosts::getAll6(const IOAddress& address) const {
+    ConstHostCollection collection;
+    getAllInternal6<ConstHostCollection>(address, collection);
+    return (collection);
+}
+
+HostCollection
+CfgHosts::getAll6(const IOAddress& address) {
+    HostCollection collection;
+    getAllInternal6<HostCollection>(address, collection);
+    return (collection);
+}
+
 template<typename Storage>
 void
 CfgHosts::getAllInternal(const std::vector<uint8_t>& identifier,
@@ -98,6 +112,24 @@ CfgHosts::getAllInternal4(const IOAddress& address, Storage& storage) const {
     }
 }
 
+template<typename Storage>
+void
+CfgHosts::getAllInternal6(const IOAddress& address, Storage& storage) const {
+    // Must not specify address other than IPv6.
+    if (!address.isV6()) {
+        isc_throw(BadHostAddress, "must specify an IPv6 address when searching"
+                  " for a host, specified address was " << address);
+    }
+    // Search for the Host using the reserved IPv4 address as a key.
+    const HostContainerIndex1& idx = hosts_.get<1>();
+    HostContainerIndex1Range r = idx.equal_range(address);
+    // Append each Host object to the storage.
+    for (HostContainerIndex1::iterator host = r.first; host != r.second;
+         ++host) {
+        storage.push_back(*host);
+    }
+}
+
 
 ConstHostPtr
 CfgHosts::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
@@ -151,6 +183,19 @@ CfgHosts::get6(const IOAddress&, const uint8_t) {
     isc_throw(isc::NotImplemented, "get6(prefix, len) is not implemented");
 }
 
+ConstHostPtr
+CfgHosts::get6(const SubnetID& subnet_id, const IOAddress& address) const {
+    ConstHostCollection hosts = getAll6(address);
+    for (ConstHostCollection::const_iterator host = hosts.begin();
+         host != hosts.end(); ++host) {
+        if ((*host)->getIPv4SubnetID() == subnet_id) {
+            return (*host);
+        }
+    }
+    return (ConstHostPtr());
+}
+
+
 HostPtr
 CfgHosts::getHostInternal(const SubnetID& subnet_id, const bool subnet6,
                           const HWAddrPtr& hwaddr, const DuidPtr& duid) const {
@@ -207,6 +252,19 @@ CfgHosts::add(const HostPtr& host) {
         isc_throw(BadValue, "must not use both IPv4 and IPv6 subnet ids of"
                   " 0 when adding new host reservation");
     }
+
+    if (host->getIPv4SubnetID() != 0) {
+        add4(host);
+    }
+
+    if (host->getIPv6SubnetID() != 0) {
+        add6(host);
+    }
+}
+
+void
+CfgHosts::add4(const HostPtr& host) {
+
     /// @todo This may need further sanity checks.
     HWAddrPtr hwaddr = host->getHWAddress();
     DuidPtr duid = host->getDuid();
@@ -236,8 +294,22 @@ CfgHosts::add(const HostPtr& host) {
                   << "' to the IPv4 subnet id '" << host->getIPv4SubnetID()
                   << "' as this host has already been added");
 
+    }
+    /// @todo This may need further sanity checks.
+
+    // This is a new instance - add it.
+    hosts_.insert(host);
+}
+
+void
+CfgHosts::add6(const HostPtr& host) {
+
+    /// @todo This may need further sanity checks.
+    HWAddrPtr hwaddr = host->getHWAddress();
+    DuidPtr duid = host->getDuid();
+
     // Check for duplicates for the specified IPv6 subnet.
-    } else if (host->getIPv6SubnetID() &&
+    if (host->getIPv6SubnetID() &&
                get6(host->getIPv6SubnetID(), duid, hwaddr)) {
         isc_throw(DuplicateHost, "failed to add new host using the HW"
                   " address '" << (hwaddr ? hwaddr->toText(false) : "(null)")
@@ -246,10 +318,29 @@ CfgHosts::add(const HostPtr& host) {
                   << "' as this host has already been added");
     }
 
-    /// @todo This may need further sanity checks.
+    // Now insert it into hosts_, which will be used for finding hosts
+    // based on their HW or DUID addresses. It cannot be used for
+    // finding IPv6 hosts by their IPv6 addresses, as there may be multiple
+    // addresses for a given host. However, insert only if this
+    // host doesn't have v4 subnet-id. If it does, it was just added
+    // by the previous call to add4().
+    if (! host->getIPv4SubnetID()) {
+        hosts_.insert(host);
+    }
 
-    // This is a new instance - add it.
-    hosts_.insert(host);
+    // Get all reservations for this host.
+    IPv6ResrvRange reservations = host->getIPv6Reservations();
+
+    if (std::distance(reservations.first, reservations.second) == 0) {
+
+        /// @todo: We don't handle address-less reservations yet
+        return;
+    }
+
+    for (IPv6ResrvIterator it = reservations.first; it != reservations.second;
+         ++it) {
+        hosts6_.insert(HostResrv6Tuple(it->second, host));
+    }
 }
 
 } // end of namespace isc::dhcp

+ 90 - 0
src/lib/dhcpsrv/cfg_hosts.h

@@ -95,6 +95,28 @@ public:
     virtual HostCollection
     getAll4(const asiolink::IOAddress& address);
 
+    /// @brief Returns a collection of hosts using the specified IPv6 address.
+    ///
+    /// This method may return multiple @c Host objects if they are connected
+    /// to different subnets.
+    ///
+    /// @param address IPv6 address for which the @c Host object is searched.
+    ///
+    /// @return Collection of const @c Host objects.
+    virtual ConstHostCollection
+    getAll6(const asiolink::IOAddress& address) const;
+
+    /// @brief Returns a collection of hosts using the specified IPv6 address.
+    ///
+    /// This method may return multiple @c Host objects if they are connected
+    /// to different subnets.
+    ///
+    /// @param address IPv6 address for which the @c Host object is searched.
+    ///
+    /// @return Collection of const @c Host objects.
+    virtual HostCollection
+    getAll6(const asiolink::IOAddress& address);
+
     /// @brief Returns a host connected to the IPv4 subnet and matching
     /// specified identifiers.
     ///
@@ -183,6 +205,25 @@ public:
     virtual HostPtr
     get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len);
 
+    /// @brief Returns a host connected to the IPv6 subnet and having
+    /// a reservation for a specified IPv6 address.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param address reserved IPv6 address.
+    ///
+    /// @return Const @c Host object using a specified IPv6 address.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
+
+    /// @brief Returns a host connected to the IPv6 subnet and having
+    /// a reservation for a specified IPv6 address.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param address reserved IPv6 address.
+    ///
+    /// @return Const @c Host object using a specified IPv6 address.
+    virtual HostPtr
+    get6(const SubnetID& subnet_id, const asiolink::IOAddress& address);
 
     /// @brief Adds a new host to the collection.
     ///
@@ -241,6 +282,21 @@ private:
     void getAllInternal4(const asiolink::IOAddress& address,
                          Storage& storage) const;
 
+    /// @brief Returns @c Host objects for the specified IPv6 address.
+    ///
+    /// This private method is called by the @c CfgHosts::getAll6 methods
+    /// to retrieve the @c Host for which the specified IPv6 address is
+    /// reserved. The retrieved objects are appended to the @c storage
+    /// container.
+    ///
+    /// @param address IPv6 address.
+    /// @param [out] storage Container to which the retrieved objects are
+    /// appended.
+    /// @tparam One of the @c ConstHostCollection or @c HostCollection.
+    template<typename Storage>
+    void getAllInternal6(const asiolink::IOAddress& address,
+                         Storage& storage) const;
+
     /// @brief Returns @c Host object connected to a subnet.
     ///
     /// This private method returns a pointer to the @c Host object identified
@@ -260,9 +316,43 @@ private:
                             const HWAddrPtr& hwaddr,
                             const DuidPtr& duid) const;
 
+
+
+    /// @brief Adds a new host to the v4 collection.
+    ///
+    /// This is an internal method called by public @ref add.
+    ///
+    /// @param host Pointer to the new @c Host object being added.
+    ///
+    /// @throw DuplicateHost If a host for a particular HW address or DUID
+    /// has already been added to the IPv4 subnet.
+    virtual void add4(const HostPtr& host);
+
+    /// @brief Adds a new host to the v6 collection.
+    ///
+    /// This is an internal method called by public @ref add.
+    ///
+    /// @param host Pointer to the new @c Host object being added.
+    ///
+    /// @throw DuplicateHost If a host for a particular HW address or DUID
+    /// or for the particular address or prefix has already been added to
+    /// the IPv6 subnet.
+    virtual void add6(const HostPtr& host);
+
     /// @brief Multi-index container holding @c Host objects.
+    ///
+    /// It can be used for finding hosts by the following criteria:
+    /// - IPv4 address
+    /// - DUID
+    /// - HW/MAC address
     HostContainer hosts_;
 
+    /// @brief Multi-index container holding @c Host objects with v6 reservations.
+    ///
+    /// It can be used for finding hosts by the following criteria:
+    /// - IPv6 address
+    /// - IPv6 prefix
+    HostContainer6 hosts6_;
 };
 
 /// @name Pointers to the @c CfgHosts objects.

+ 6 - 0
src/lib/dhcpsrv/host.cc

@@ -194,6 +194,12 @@ Host::getIPv6Reservations(const IPv6Resrv::Type& type) const {
     return (ipv6_reservations_.equal_range(type));
 }
 
+IPv6ResrvRange
+Host::getIPv6Reservations() const {
+    return (IPv6ResrvRange(ipv6_reservations_.begin(),
+                           ipv6_reservations_.end()));
+}
+
 bool
 Host::hasIPv6Reservation() const {
     return (!ipv6_reservations_.empty());

+ 6 - 0
src/lib/dhcpsrv/host.h

@@ -352,6 +352,12 @@ public:
     /// the specified type.
     IPv6ResrvRange getIPv6Reservations(const IPv6Resrv::Type& type) const;
 
+    /// @brief Returns all IPv6 reservations.
+    ///
+    /// @return A range of iterators pointing to the reservations of
+    /// the specified type.
+    IPv6ResrvRange getIPv6Reservations() const;
+
     /// @brief Checks if there is at least one IPv6 reservation for this host.
     ///
     /// @return true if there is a reservation for the host, false otherwise.

+ 69 - 0
src/lib/dhcpsrv/host_container.h

@@ -16,9 +16,11 @@
 #define HOST_CONTAINER_H
 
 #include <dhcpsrv/host.h>
+#include <dhcpsrv/subnet_id.h>
 #include <boost/multi_index_container.hpp>
 #include <boost/multi_index/composite_key.hpp>
 #include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/member.hpp>
 #include <boost/multi_index/ordered_index.hpp>
 
 namespace isc {
@@ -96,6 +98,73 @@ typedef HostContainer::nth_index<1>::type HostContainerIndex1;
 typedef std::pair<HostContainerIndex1::iterator,
                   HostContainerIndex1::iterator> HostContainerIndex1Range;
 
+/// @brief Defines one entry for the Host Container for v6 hosts
+///
+/// It's essentially a pair of (IPv6 reservation, Host pointer).
+struct HostResrv6Tuple {
+
+    /// @brief Default constructor
+    HostResrv6Tuple(const IPv6Resrv& resrv, const ConstHostPtr& host)
+    :resrv_(resrv), host_(host), subnet_id_(host? host->getIPv6SubnetID() : 0) {
+    }
+
+    const IPv6Resrv resrv_;
+    ConstHostPtr host_;
+    const SubnetID subnet_id_;
+
+    const asiolink::IOAddress& getKey() const {
+        return (resrv_.getPrefix());
+    }
+};
+
+/// @brief Multi-index container holding IPv6 reservations.
+///
+/// This container holds HostResrv6Tuples, i.e. pairs of (IPv6Resrv, HostPtr)
+/// pieces of information. This is needed for efficiently finding a host
+/// for a given IPv6 address or prefix.
+typedef boost::multi_index_container<
+
+    /// This containers stores (IPv6Resrv, HostPtr) tuples
+    HostResrv6Tuple,
+
+    /// Start specification of indexes here.
+    boost::multi_index::indexed_by<
+
+        /// First index is used to search by an address.
+        boost::multi_index::ordered_non_unique<
+
+            /// Address is extracted by calling IPv6Resrv::getPrefix()
+            /// and it will return an IOAddress object.
+            boost::multi_index::const_mem_fun<
+                HostResrv6Tuple, const asiolink::IOAddress&,
+                &HostResrv6Tuple::getKey
+            >
+        >,
+
+        /// Second index is used to search by (subnet_id, address) pair
+        /// @todo: Let's make the first index working first.
+        boost::multi_index::ordered_non_unique<
+
+            boost::multi_index::composite_key<
+                  HostResrv6Tuple,
+
+                  boost::multi_index::member<
+                    HostResrv6Tuple, const SubnetID,
+                    &HostResrv6Tuple::subnet_id_
+                    >,
+
+                /// Address is extracted by calling IPv6Resrv::getPrefix()
+                /// and it will return an IOAddress object.
+                boost::multi_index::const_mem_fun<
+                    HostResrv6Tuple, const asiolink::IOAddress&,
+                    &HostResrv6Tuple::getKey
+                >
+           >
+        >
+
+> HostContainer6;
+
+
 }
 }
 

+ 11 - 0
src/lib/dhcpsrv/host_mgr.cc

@@ -118,6 +118,17 @@ HostMgr::get6(const IOAddress& prefix, const uint8_t prefix_len) const {
     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) {
+        host = alternate_source->get6(subnet_id, addr);
+    }
+    return (host);
+}
+
+
 void
 HostMgr::add(const HostPtr&) {
     isc_throw(isc::NotImplemented, "HostMgr::add is not implemented");

+ 9 - 0
src/lib/dhcpsrv/host_mgr.h

@@ -181,6 +181,15 @@ public:
     virtual ConstHostPtr
     get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const;
 
+    /// @brief Returns a host from specific subnet and reserved address.
+    ///
+    /// @param subnet_id subnet identfier.
+    /// @param addr specified address.
+    ///
+    /// @return Const @c host object that has a reservation for specified address.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id, const asiolink::IOAddress& addr) const;
+
     /// @brief Adds a new host to the alternate data source.
     ///
     /// This method will throw an exception if no alternate data source is