Browse Source

[3563] Extended AllocEngine with HostMgr::get6() calls.

Tomek Mrugalski 10 years ago
parent
commit
02d214b3a1
2 changed files with 99 additions and 29 deletions
  1. 84 29
      src/lib/dhcpsrv/alloc_engine.cc
  2. 15 0
      src/lib/dhcpsrv/subnet.h

+ 84 - 29
src/lib/dhcpsrv/alloc_engine.cc

@@ -15,6 +15,7 @@
 #include <dhcpsrv/alloc_engine.h>
 #include <dhcpsrv/dhcpsrv_log.h>
 #include <dhcpsrv/host_mgr.h>
+#include <dhcpsrv/host.h>
 #include <dhcpsrv/lease_mgr_factory.h>
 
 #include <hooks/server_hooks.h>
@@ -476,39 +477,56 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
         /// @todo: We support only one hint for now
         Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(ctx.type_, hint);
         if (!lease) {
-            /// @todo: check if the hint is reserved once we have host
-            /// support implemented
 
-            // The hint is valid and not currently used, let's create a
-            // lease for it
-            lease = createLease6(ctx, hint, pool->getLength());
-
-            // 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 we need to continue the regular
-            // allocation path.
-            if (lease) {
+            // In-pool reservations: Check if this address is reserved for someone
+            // else. There is no need to check for whom it is reserved, because if
+            // it has been reserved for us we would have already allocated a lease.
+
+            /// @todo: BROKEN this call is broken. It tries to convert getID()
+            /// to IOAddress::uint32_t()
+            if (!ctx.subnet_->allowInPoolReservations() ||
+                !HostMgr::instance().get6(ctx.subnet_->getID(), hint)) {
+                // If the in-pool reservations are disabled, or there is no
+                // reservation for a given hint, we're good to go.
+
+                // The hint is valid and not currently used, let's create a
+                // lease for it
+                lease = createLease6(ctx, hint, pool->getLength());
+
+                // 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 we need to continue the regular
+                // allocation path.
+                if (lease) {
 
-                /// @todo: We support only one lease per ia for now
-                Lease6Collection collection;
-                collection.push_back(lease);
-                return (collection);
+                    /// @todo: We support only one lease per ia for now
+                    Lease6Collection collection;
+                    collection.push_back(lease);
+                    return (collection);
+                }
             }
         } else {
+
+            // If the lease is expired, we may likely reuse it, but...
             if (lease->expired()) {
-                // Copy an existing, expired lease so as it can be returned
-                // to the caller.
-                Lease6Ptr old_lease(new Lease6(*lease));
-                ctx.old_leases_.push_back(old_lease);
 
-                /// We found a lease and it is expired, so we can reuse it
-                lease = reuseExpiredLease(lease, ctx, pool->getLength());
+                // Let's check if there is a reservation for this address.
+                if (!ctx.subnet_->allowInPoolReservations() ||
+                    !HostMgr::instance().get6(ctx.subnet_->getID(), hint)) {
 
-                /// @todo: We support only one lease per ia for now
-                leases.push_back(lease);
-                return (leases);
-            }
+                    // Copy an existing, expired lease so as it can be returned
+                    // to the caller.
+                    Lease6Ptr old_lease(new Lease6(*lease));
+                    ctx.old_leases_.push_back(old_lease);
+
+                    /// We found a lease and it is expired, so we can reuse it
+                    lease = reuseExpiredLease(lease, ctx, pool->getLength());
 
+                    /// @todo: We support only one lease per ia for now
+                    leases.push_back(lease);
+                    return (leases);
+                }
+            }
         }
     }
 
@@ -532,8 +550,15 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
     do {
         IOAddress candidate = allocator->pickAddress(ctx.subnet_, ctx.duid_, hint);
 
-        /// @todo: check if the address is reserved once we have host support
-        /// implemented
+        /// In-pool reservations: Check if this address is reserved for someone
+        /// else. There is no need to check for whom it is reserved, because if
+        /// it has been reserved for us we would have already allocated a lease.
+        if (ctx.subnet_->allowInPoolReservations() &&
+            HostMgr::instance().get6(ctx.subnet_->getID(), candidate)) {
+
+            // Don't allocate.
+            continue;
+        }
 
         // The first step is to find out prefix length. It is 128 for
         // non-PD leases.
@@ -592,10 +617,40 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
 
 void
 AllocEngine::allocateReservedLeases6(ClientContext6& ctx, Lease6Collection& existing_leases) {
-    /// @todo
-    if (!ctx.host_ || existing_leases.empty()) {
+
+    // If there are no reservations or the reservation is v4, there's nothing to do.
+    if (!ctx.host_ || ctx.host_->hasIPv6Reservation()) {
+        return;
+    }
+
+    // Let's convert this from Lease::Type to IPv6Reserv::Type
+    IPv6Resrv::Type type = ctx.type_ == Lease::TYPE_NA ? IPv6Resrv::TYPE_NA : IPv6Resrv::TYPE_PD;
+
+    // Get the IPv6 reservations of specified type.
+    const IPv6ResrvRange& reservs = ctx.host_->getIPv6Reservations(type);
+
+    if (std::distance(reservs.first, reservs.second) == 0) {
+        // No reservations? We're done here.
         return;
     }
+
+    for (IPv6ResrvIterator resv = reservs.first; resv != reservs.second; ++resv) {
+        // We do have a reservation for addr.
+        IOAddress addr = resv->second.getPrefix();
+        uint8_t prefix_len = resv->second.getPrefixLen();
+
+        // If there's a lease for this address, let's not create it.
+        // It doesn't matter whether it is for this client or for someone else.
+        if (LeaseMgrFactory::instance().getLease6(ctx.type_, addr)) {
+            continue;
+        }
+
+        // Ok, let's create a new lease...
+        Lease6Ptr lease = createLease6(ctx, addr, prefix_len);
+
+        // ... and add it to the existing leases list.
+        existing_leases.push_back(lease);
+    }
 }
 
 void

+ 15 - 0
src/lib/dhcpsrv/subnet.h

@@ -284,6 +284,21 @@ public:
     void
     allowClientClass(const isc::dhcp::ClientClass& class_name);
 
+    /// @brief Specifies whether in-pool host reservations are allowed.
+    ///
+    /// Host reservations may be either in-pool (they reserve an address that
+    /// is in the dynamic pool) or out-of-pool (they reserve an address that is
+    /// not in the dynamic pool).
+    ///
+    /// @todo: implement this.
+    ///
+    /// @return whether in-pool host reservations are allowed.
+    bool
+    allowInPoolReservations() {
+        /// @todo: Make this configurable.
+        return (true);
+    }
+
 protected:
     /// @brief Returns all pools (non-const variant)
     ///