Browse Source

[5306] Implemented getNextSubnet() function for subnets.

Marcin Siodelski 7 years ago
parent
commit
c76416e5d4

+ 8 - 27
src/lib/dhcpsrv/alloc_engine.cc

@@ -2192,9 +2192,7 @@ void findClientLease(AllocEngine::ClientContext4& ctx, Lease4Ptr& client_lease)
         // Some of the subnets within a shared network may not be allowed
         // for the client if classification restrictions have been applied.
         if (!subnet->clientSupported(ctx.query_->getClasses())) {
-            if (network) {
-                subnet = network->getNextSubnet(original_subnet, subnet);
-            }
+            subnet = subnet->getNextSubnet(original_subnet);
             continue;
         }
 
@@ -2235,7 +2233,7 @@ void findClientLease(AllocEngine::ClientContext4& ctx, Lease4Ptr& client_lease)
             subnet.reset();
 
         } else {
-            subnet = network->getNextSubnet(original_subnet, subnet);
+            subnet = subnet->getNextSubnet(original_subnet);
         }
     }
 }
@@ -2271,15 +2269,7 @@ inAllowedPool(AllocEngine::ClientContext4& ctx, const IOAddress& address) {
             }
         }
 
-        if (network) {
-            // Address is not within pools or client class not supported, so
-            // let's proceed to the next subnet.
-            current_subnet = network->getNextSubnet(ctx.subnet_, current_subnet);
-
-        } else {
-            // No shared network, so there are no more subnets to try.
-            current_subnet.reset();
-        }
+        current_subnet = current_subnet->getNextSubnet(ctx.subnet_);
     }
 
     return (false);
@@ -2966,9 +2956,7 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) {
         // Some of the subnets within a shared network may not be allowed
         // for the client if classification restrictions have been applied.
         if (!subnet->clientSupported(ctx.query_->getClasses())) {
-            if (network) {
-                subnet = network->getNextSubnet(original_subnet, subnet);
-            }
+            subnet = subnet->getNextSubnet(original_subnet);
             continue;
         }
 
@@ -2993,23 +2981,16 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) {
                     break;
                 }
             }
+            ++total_attempts;
         }
 
-        total_attempts += max_attempts;
-
-        // If our current subnet belongs to a shared network, let's try other
-        // subnets in the same shared network.
-        if (network) {
-            subnet = network->getNextSubnet(original_subnet, subnet);
+        // This pointer may be set to NULL if hooks set SKIP status.
+        if (subnet) {
+            subnet = subnet->getNextSubnet(original_subnet);
 
             if (subnet) {
                 ctx.subnet_ = subnet;
             }
-
-        } else {
-            // Subnet doesn't belong to a shared network so we have no more
-            // subnets/address pools to try. The client won't get the lease.
-            subnet.reset();
         }
     }
 

+ 5 - 14
src/lib/dhcpsrv/shared_network.cc

@@ -157,16 +157,7 @@ public:
     template<typename SubnetPtrType, typename SubnetCollectionType>
     static SubnetPtrType getNextSubnet(const SubnetCollectionType& subnets,
                                        const SubnetPtrType& first_subnet,
-                                       const SubnetPtrType& current_subnet) {
-        // Current subnet must not be null. The caller must explicitly set it
-        // to one of the pointers that belong to this shared network, typically
-        // to a selected subnet.
-        if (!current_subnet) {
-            isc_throw(BadValue, "null subnet specified for a shared"
-                      " network while searching for next subnet is this"
-                      " network");
-        }
-
+                                       const SubnetID& current_subnet) {
         // It is ok to have a shared network without any subnets, but in this
         // case there is nothing else we can return but null pointer.
         if (subnets.empty()) {
@@ -177,9 +168,9 @@ public:
         // subnet must exist in this container, thus we throw if the iterator
         // is not found.
         const auto& index = subnets.template get<SubnetSubnetIdIndexTag>();
-        auto subnet_id_it = index.find(current_subnet->getID());
+        auto subnet_id_it = index.find(current_subnet);
         if (subnet_id_it == index.cend()) {
-            isc_throw(BadValue, "no such subnet " << current_subnet->getID()
+            isc_throw(BadValue, "no such subnet " << current_subnet
                       << " within shared network");
         }
 
@@ -235,7 +226,7 @@ SharedNetwork4::getSubnet(const SubnetID& subnet_id) const {
 
 Subnet4Ptr
 SharedNetwork4::getNextSubnet(const Subnet4Ptr& first_subnet,
-                              const Subnet4Ptr& current_subnet) const {
+                              const SubnetID& current_subnet) const {
     return (Impl::getNextSubnet(subnets_, first_subnet, current_subnet));
 }
 
@@ -283,7 +274,7 @@ SharedNetwork6::getSubnet(const SubnetID& subnet_id) const {
 
 Subnet6Ptr
 SharedNetwork6::getNextSubnet(const Subnet6Ptr& first_subnet,
-                              const Subnet6Ptr& current_subnet) const {
+                              const SubnetID& current_subnet) const {
     return (Impl::getNextSubnet(subnets_, first_subnet,
                                          current_subnet));
 }

+ 4 - 4
src/lib/dhcpsrv/shared_network.h

@@ -103,7 +103,7 @@ public:
     /// @param first_subnet Pointer to a subnet from which the caller is
     /// iterating over subnets within shared network. This is typically a
     /// subnet selected during "subnet selection" step.
-    /// @param current_subnet Pointer to a subnet for which next subnet is
+    /// @param current_subnet Identifier of a subnet for which next subnet is
     /// to be found.
     ///
     /// @return Pointer to next subnet or null pointer if no more subnets found.
@@ -111,7 +111,7 @@ public:
     /// @throw isc::BadValue if invalid arguments specified, e.g. unable to
     /// find first or current subnet within shared network.
     Subnet4Ptr getNextSubnet(const Subnet4Ptr& first_subnet,
-                             const Subnet4Ptr& current_subnet) const;
+                             const SubnetID& current_subnet) const;
 
     /// @brief Unparses shared network object.
     ///
@@ -226,7 +226,7 @@ public:
     /// @param first_subnet Pointer to a subnet from which the caller is
     /// iterating over subnets within shared network. This is typically a
     /// subnet selected during "subnet selection" step.
-    /// @param current_subnet Pointer to a subnet for which next subnet is
+    /// @param current_subnet Identifier of a subnet for which next subnet is
     /// to be found.
     ///
     /// @return Pointer to next subnet or null pointer if no more subnets found.
@@ -234,7 +234,7 @@ public:
     /// @throw isc::BadValue if invalid arguments specified, e.g. unable to
     /// find first or current subnet within shared network.
     Subnet6Ptr getNextSubnet(const Subnet6Ptr& first_subnet,
-                             const Subnet6Ptr& current_subnet) const;
+                             const SubnetID& current_subnet) const;
 
     /// @brief Unparses shared network object.
     ///

+ 23 - 0
src/lib/dhcpsrv/subnet.cc

@@ -9,6 +9,7 @@
 #include <asiolink/io_address.h>
 #include <dhcp/option_space.h>
 #include <dhcpsrv/addr_utilities.h>
+#include <dhcpsrv/shared_network.h>
 #include <dhcpsrv/subnet.h>
 #include <algorithm>
 #include <sstream>
@@ -176,6 +177,17 @@ Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
     setValid(valid_lifetime);
 }
 
+Subnet4Ptr
+Subnet4::getNextSubnet(const Subnet4Ptr& first_subnet) const {
+    SharedNetwork4Ptr network;
+    getSharedNetwork(network);
+    if (network) {
+        return (network->getNextSubnet(first_subnet, getID()));
+    }
+
+    return (Subnet4Ptr());
+}
+
 bool
 Subnet4::clientSupported(const isc::dhcp::ClientClasses& client_classes) const {
     NetworkPtr network;
@@ -450,6 +462,17 @@ void Subnet6::checkType(Lease::Type type) const {
     }
 }
 
+Subnet6Ptr
+Subnet6::getNextSubnet(const Subnet6Ptr& first_subnet) const {
+    SharedNetwork6Ptr network;
+    getSharedNetwork(network);
+    if (network) {
+        return (network->getNextSubnet(first_subnet, getID()));
+    }
+
+    return (Subnet6Ptr());
+}
+
 bool
 Subnet6::clientSupported(const isc::dhcp::ClientClasses& client_classes) const {
     NetworkPtr network;

+ 41 - 10
src/lib/dhcpsrv/subnet.h

@@ -371,6 +371,14 @@ protected:
 typedef boost::shared_ptr<Subnet> SubnetPtr;
 
 
+class Subnet4;
+
+/// @brief A const pointer to a @c Subnet4 object.
+typedef boost::shared_ptr<const Subnet4> ConstSubnet4Ptr;
+
+/// @brief A pointer to a @c Subnet4 object.
+typedef boost::shared_ptr<Subnet4> Subnet4Ptr;
+
 /// @brief A configuration holder for IPv4 subnet.
 ///
 /// This class represents an IPv4 subnet.
@@ -394,6 +402,20 @@ public:
             const Triplet<uint32_t>& valid_lifetime,
             const SubnetID id = 0);
 
+    /// @brief Returns next subnet within shared network.
+    ///
+    /// If the current subnet doesn't belong to any shared network or if
+    /// the next subnet is the same as first subnet (specified in the
+    /// arguments) a NULL pointer is returned.
+    ///
+    /// @param first_subnet Pointer to the subnet from which iterations have
+    /// started.
+    ///
+    /// @return Pointer to the next subnet or NULL pointer if the next subnet
+    /// is the first subnet or if the current subnet doesn't belong to a
+    /// shared network.
+    Subnet4Ptr getNextSubnet(const Subnet4Ptr& first_subnet) const;
+
     /// @brief Checks whether this subnet and parent shared network supports
     /// the client that belongs to specified classes.
     ///
@@ -464,12 +486,13 @@ private:
     Cfg4o6 dhcp4o6_;
 };
 
-/// @brief A const pointer to a @c Subnet4 object.
-typedef boost::shared_ptr<const Subnet4> ConstSubnet4Ptr;
+class Subnet6;
 
-/// @brief A pointer to a @c Subnet4 object.
-typedef boost::shared_ptr<Subnet4> Subnet4Ptr;
+/// @brief A const pointer to a @c Subnet6 object.
+typedef boost::shared_ptr<const Subnet6> ConstSubnet6Ptr;
 
+/// @brief A pointer to a Subnet6 object
+typedef boost::shared_ptr<Subnet6> Subnet6Ptr;
 
 /// @brief A configuration holder for IPv6 subnet.
 ///
@@ -496,6 +519,20 @@ public:
             const Triplet<uint32_t>& valid_lifetime,
             const SubnetID id = 0);
 
+    /// @brief Returns next subnet within shared network.
+    ///
+    /// If the current subnet doesn't belong to any shared network or if
+    /// the next subnet is the same as first subnet (specified in the
+    /// arguments) a NULL pointer is returned.
+    ///
+    /// @param first_subnet Pointer to the subnet from which iterations have
+    /// started.
+    ///
+    /// @return Pointer to the next subnet or NULL pointer if the next subnet
+    /// is the first subnet or if the current subnet doesn't belong to a
+    /// shared network.
+    Subnet6Ptr getNextSubnet(const Subnet6Ptr& first_subnet) const;
+
     /// @brief Checks whether this subnet and parent shared network supports
     /// the client that belongs to specified classes.
     ///
@@ -533,12 +570,6 @@ private:
 
 };
 
-/// @brief A const pointer to a @c Subnet6 object.
-typedef boost::shared_ptr<const Subnet6> ConstSubnet6Ptr;
-
-/// @brief A pointer to a Subnet6 object
-typedef boost::shared_ptr<Subnet6> Subnet6Ptr;
-
 /// @name Definition of the multi index container holding subnet information
 ///
 //@{

+ 2 - 2
src/lib/dhcpsrv/tests/shared_network_unittest.cc

@@ -164,7 +164,7 @@ TEST(SharedNetwork4Test, getNextSubnet) {
         // Iterate over the subnets starting from the subnet with index i.
         for (auto j = 0; j < subnets.size(); ++j) {
             // Get next subnet (following the one currently in s).
-            s = networks[0]->getNextSubnet(subnets[i], s);
+            s = networks[0]->getNextSubnet(subnets[i], s->getID());
             // The last iteration should return empty pointer to indicate end of
             // the subnets within shared network. If we're not at last iteration
             // check that the subnet identifier of the returned subnet is valid.
@@ -426,7 +426,7 @@ TEST(SharedNetwork6Test, getNextSubnet) {
         // Iterate over the subnets starting from the subnet with index i.
         for (auto j = 0; j < subnets.size(); ++j) {
             // Get next subnet (following the one currently in s).
-            s = networks[0]->getNextSubnet(subnets[i], s);
+            s = networks[0]->getNextSubnet(subnets[i], s->getID());
             // The last iteration should return empty pointer to indicate end of
             // the subnets within shared network. If we're not at last iteration
             // check that the subnet identifier of the returned subnet is valid.