Browse Source

[3153] PD renewal implemented.

Tomek Mrugalski 11 years ago
parent
commit
daf53e75f5
3 changed files with 146 additions and 5 deletions
  1. 19 4
      src/bin/dhcp6/dhcp6_messages.mes
  2. 113 1
      src/bin/dhcp6/dhcp6_srv.cc
  3. 14 0
      src/bin/dhcp6/dhcp6_srv.h

+ 19 - 4
src/bin/dhcp6/dhcp6_messages.mes

@@ -452,10 +452,25 @@ This warning message is printed when client attempts to release a lease,
 but no such lease is known by the server. See DHCP6_UNKNOWN_RENEW for
 possible reasons for such behavior.
 
-% DHCP6_UNKNOWN_RENEW received RENEW from client (duid=%1, iaid=%2) in subnet %3
-This warning message is printed when client attempts to renew a lease,
-but no such lease is known by the server. It typically means that
-client has attempted to use its lease past its lifetime: causes of this
+% DHCP6_UNKNOWN_RENEW_NA received unknown IA_NA RENEW from client (duid=%1, iaid=%2) in subnet %3
+This warning message is printed when client attempts to renew an address lease
+(in IA_NA option), but no such lease is known by the server. It typically means
+that client has attempted to use its lease past its lifetime: causes of this
+include a adjustment of the clients date/time setting or poor support
+for sleep/recovery. A properly implemented client will recover from such
+a situation by restarting the lease allocation process after receiving
+a negative reply from the server.
+
+An alternative cause could be that the server has lost its database
+recently and does not recognize its well-behaving clients. This is more
+probable if you see many such messages. Clients will recover from this,
+but they will most likely get a different IP addresses and experience
+a brief service interruption.
+
+% DHCP6_UNKNOWN_RENEW_PD received unknown IA_NA RENEW from client (duid=%1, iaid=%2) in subnet %3
+This warning message is printed when client attempts to renew an address lease
+(in IA_NA option), but no such lease is known by the server. It typically means
+that client has attempted to use its lease past its lifetime: causes of this
 include a adjustment of the clients date/time setting or poor support
 for sleep/recovery. A properly implemented client will recover from such
 a situation by restarting the lease allocation process after receiving

+ 113 - 1
src/bin/dhcp6/dhcp6_srv.cc

@@ -1454,7 +1454,7 @@ Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
         ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
                           "Sorry, no known leases for this duid/iaid."));
 
-        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_UNKNOWN_RENEW)
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_UNKNOWN_RENEW_NA)
             .arg(duid->toText())
             .arg(ia->getIAID())
             .arg(subnet->toText());
@@ -1563,6 +1563,108 @@ Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
     return (ia_rsp);
 }
 
+OptionPtr
+Dhcpv6Srv::renewIA_PD(const Subnet6Ptr& subnet, const DuidPtr& duid,
+                      const Pkt6Ptr& query, boost::shared_ptr<Option6IA> ia) {
+    if (!subnet) {
+        // There's no subnet select for this client. There's nothing to renew.
+        boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_PD, ia->getIAID()));
+
+        // Insert status code NoAddrsAvail.
+        ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
+                          "Sorry, no known leases for this duid/iaid."));
+
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_RENEW_UNKNOWN_SUBNET)
+            .arg(duid->toText())
+            .arg(ia->getIAID());
+
+        return (ia_rsp);
+    }
+
+    Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD,
+                                                            *duid, ia->getIAID(),
+                                                            subnet->getID());
+
+    if (!lease) {
+        // client renewing a lease that we don't know about.
+
+        // Create empty IA_NA option with IAID matching the request.
+        boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_PD, ia->getIAID()));
+
+        // Insert status code NoAddrsAvail.
+        ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
+                          "Sorry, no known leases for this duid/iaid."));
+
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_UNKNOWN_RENEW_PD)
+            .arg(duid->toText())
+            .arg(ia->getIAID())
+            .arg(subnet->toText());
+
+        return (ia_rsp);
+    }
+
+    // Keep the old data in case the callout tells us to skip update
+    Lease6 old_data = *lease;
+
+    lease->preferred_lft_ = subnet->getPreferred();
+    lease->valid_lft_ = subnet->getValid();
+    lease->t1_ = subnet->getT1();
+    lease->t2_ = subnet->getT2();
+    lease->cltt_ = time(NULL);
+
+    // Create empty IA_NA option with IAID matching the request.
+    boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_PD, ia->getIAID()));
+
+    ia_rsp->setT1(subnet->getT1());
+    ia_rsp->setT2(subnet->getT2());
+
+    boost::shared_ptr<Option6IAPrefix>
+      prefix(new Option6IAPrefix(D6O_IAPREFIX, lease->addr_, lease->prefixlen_,
+                                 lease->preferred_lft_, lease->valid_lft_));
+    ia_rsp->addOption(prefix);
+
+    bool skip = false;
+    // Execute all callouts registered for packet6_send
+    if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_lease6_renew_)) {
+        CalloutHandlePtr callout_handle = getCalloutHandle(query);
+
+        // Delete all previous arguments
+        callout_handle->deleteAllArguments();
+
+        // Pass the original packet
+        callout_handle->setArgument("query6", query);
+
+        // Pass the lease to be updated
+        callout_handle->setArgument("lease6", lease);
+
+        // Pass the IA option to be sent in response
+        callout_handle->setArgument("ia_pd", ia_rsp);
+
+        // Call all installed callouts
+        HooksManager::callCallouts(Hooks.hook_index_lease6_renew_, *callout_handle);
+
+        // Callouts decided to skip the next processing step. The next
+        // processing step would to actually renew the lease, so skip at this
+        // stage means "keep the old lease as it is".
+        if (callout_handle->getSkip()) {
+            skip = true;
+            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_LEASE6_RENEW_SKIP);
+        }
+    }
+
+    if (!skip) {
+        LeaseMgrFactory::instance().updateLease6(lease);
+    } else {
+        // Copy back the original date to the lease. For MySQL it doesn't make
+        // much sense, but for memfile, the Lease6Ptr points to the actual lease
+        // in memfile, so the actual update is performed when we manipulate fields
+        // of returned Lease6Ptr, the actual updateLease6() is no-op.
+        *lease = old_data;
+    }
+
+    return (ia_rsp);
+}
+
 void
 Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply,
                        const Option6ClientFqdnPtr& fqdn) {
@@ -1617,6 +1719,16 @@ Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply,
             }
             break;
         }
+        case D6O_IA_PD: {
+            OptionPtr answer_opt = renewIA_PD(subnet, duid, renew,
+                                              boost::dynamic_pointer_cast<
+                                                  Option6IA>(opt->second));
+            if (answer_opt) {
+                reply->addOption(answer_opt);
+            }
+            break;
+        }
+
         default:
             break;
         }

+ 14 - 0
src/bin/dhcp6/dhcp6_srv.h

@@ -257,6 +257,20 @@ protected:
                          const Pkt6Ptr& query, boost::shared_ptr<Option6IA> ia,
                          const Option6ClientFqdnPtr& fqdn);
 
+    /// @brief Renews specific IA_PD option
+    ///
+    /// Generates response to IA_PD in Renew. This typically includes finding a
+    /// lease that corresponds to the received prefix. If no such lease is
+    /// found, an IA_PD response is generated with an appropriate status code.
+    ///
+    /// @param subnet subnet the sender belongs to
+    /// @param duid client's duid
+    /// @param query client's message
+    /// @param ia IA_PD option that is being renewed
+    /// @return IA_PD option (server's response)
+    OptionPtr renewIA_PD(const Subnet6Ptr& subnet, const DuidPtr& duid,
+                         const Pkt6Ptr& query, boost::shared_ptr<Option6IA> ia);
+
     /// @brief Releases specific IA_NA option
     ///
     /// Generates response to IA_NA in Release message. This covers finding and