BIND 10 trac2414, updated. f63a6cabd8ecfca7465f1856a3836bdd72ea34f3 [2414] Allocation Engine is now used in dhcp6_srv.

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Oct 30 18:17:57 UTC 2012


The branch, trac2414 has been updated
       via  f63a6cabd8ecfca7465f1856a3836bdd72ea34f3 (commit)
       via  90bb56b150b1c51690dffce834bff4b91f754111 (commit)
      from  ae8d436d86973d85dbf512ca39167b41dcdb6a7c (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f63a6cabd8ecfca7465f1856a3836bdd72ea34f3
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Tue Oct 30 19:16:55 2012 +0100

    [2414] Allocation Engine is now used in dhcp6_srv.

commit 90bb56b150b1c51690dffce834bff4b91f754111
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Tue Oct 30 18:59:50 2012 +0100

    [2414] IfaceMgr now binds link-local addresses only.

-----------------------------------------------------------------------

Summary of changes:
 src/bin/dhcp6/dhcp6_messages.mes |    6 +-
 src/bin/dhcp6/dhcp6_srv.cc       |  169 +++++++++++++++++++++++++++++---------
 src/bin/dhcp6/dhcp6_srv.h        |   40 +++++++++
 src/lib/dhcp/Makefile.am         |    4 +
 src/lib/dhcp/iface_mgr.cc        |    9 ++
 5 files changed, 184 insertions(+), 44 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index 2399c19..ea0cb2a 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -50,7 +50,7 @@ The IPv6 DHCP server tried to receive a packet but an error
 occured during this attempt. The reason for the error is included in
 the message.
 
-% DHCP6_PACKET_RECEIVED %1 (type %2) packet received
+% DHCP6_PACKET_RECEIVED %1 packet received
 A debug message noting that the server has received the specified type
 of packet.  Note that a packet marked as UNKNOWN may well be a valid
 DHCP packet, just a type not expected by the server (e.g. it will report
@@ -66,10 +66,10 @@ This error is output if the server failed to assemble the data to be
 returned to the client into a valid packet.  The reason is most likely
 to be to a programming error: please raise a bug report.
 
-% DHCP6_QUERY_DATA received packet length %1, data length %2, data is <%3>
+% DHCP6_QUERY_DATA received packet length %1, data length %2, data is %3
 A debug message listing the data received from the client or relay.
 
-% DHCP6_RESPONSE_DATA responding with packet type %1 data is <%2>
+% DHCP6_RESPONSE_DATA responding with packet type %1 data is %2
 A debug message listing the data returned to the client.
 
 % DHCP6_SERVER_FAILED server failed: %1
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 74949ed..c801afc 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -28,6 +28,12 @@
 #include <util/io_utilities.h>
 #include <util/range_utilities.h>
 #include <dhcp/duid.h>
+#include <dhcp/lease_mgr.h>
+#include <dhcp/cfgmgr.h>
+#include <dhcp/option6_iaaddr.h>
+
+// @todo: Replace this with MySQL_LeaseMgr once it is merged
+#include <dhcp/tests/memfile_lease_mgr.h>
 
 using namespace isc;
 using namespace isc::asiolink;
@@ -35,20 +41,9 @@ using namespace isc::dhcp;
 using namespace isc::util;
 using namespace std;
 
-const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
-const uint32_t HARDCODED_T1 = 1500; // in seconds
-const uint32_t HARDCODED_T2 = 2600; // in seconds
-const uint32_t HARDCODED_PREFERRED_LIFETIME = 3600; // in seconds
-const uint32_t HARDCODED_VALID_LIFETIME = 7200; // in seconds
 const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";
 
 Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
-    if (port == 0) {
-        // used for testing purposes. Some tests, e.g. configuration parser,
-        // require Dhcpv6Srv object, but they don't really need it to do
-        // anything. This speed up and simplifies the tests.
-        return;
-    }
 
     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port);
 
@@ -56,13 +51,18 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
     // it may throw something if things go wrong
     try {
 
-        if (IfaceMgr::instance().countIfaces() == 0) {
-            LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES);
-            shutdown_ = true;
-            return;
-        }
+        // used for testing purposes. Some tests, e.g. configuration parser,
+        // require Dhcpv6Srv object, but they don't really need it to do
+        // anything. This speed up and simplifies the tests.
+        if (port) {
+            if (IfaceMgr::instance().countIfaces() == 0) {
+                LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES);
+                shutdown_ = true;
+                return;
+            }
 
-        IfaceMgr::instance().openSockets6(port);
+            IfaceMgr::instance().openSockets6(port);
+        }
 
         setServerID();
 
@@ -74,11 +74,20 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
         return;
     }
 
+    // Instantiate LeaseMgr
+    // @todo: Replace this with MySQL_LeaseMgr once it is merged
+    new isc::dhcp::test::Memfile_LeaseMgr("");
+
+    // Instantiate allocation engine
+    alloc_engine_ = new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100);
+
     shutdown_ = false;
 }
 
 Dhcpv6Srv::~Dhcpv6Srv() {
     IfaceMgr::instance().closeSockets();
+
+    LeaseMgr::destroy_instance();
 }
 
 void Dhcpv6Srv::shutdown() {
@@ -108,10 +117,9 @@ bool Dhcpv6Srv::run() {
                 continue;
             }
             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PACKET_RECEIVED)
-                      .arg(serverReceivedPacketName(query->getType()))
-                      .arg(query->getType());
+                      .arg(serverReceivedPacketName(query->getType()));
             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
-                      .arg(query->getType())
+                      .arg(static_cast<int>(query->getType()))
                       .arg(query->getBuffer().getLength())
                       .arg(query->toText());
 
@@ -301,33 +309,112 @@ void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& ans
     answer->addOption(dnsservers);
 }
 
+OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
+
+    // @todo: Implement Option6_StatusCode and rewrite this code here
+    vector<uint8_t> data(text.c_str(), text.c_str() + text.length());
+    data.insert(data.begin(), static_cast<uint8_t>(code % 256));
+    data.insert(data.begin(), static_cast<uint8_t>(code >> 8));
+    OptionPtr status(new Option(Option::V6, D6O_STATUS_CODE, data));
+    return (status);
+}
+
+Subnet6Ptr Dhcpv6Srv::getSubnet(const Pkt6Ptr& question) {
+    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
+
+    return (subnet);
+}
+
 void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
-    /// TODO Rewrite this once LeaseManager is implemented.
-
-    // answer client's IA (this is mostly a dummy,
-    // so let's answer only first IA and hope there is only one)
-    boost::shared_ptr<Option> ia_opt = question->getOption(D6O_IA_NA);
-    if (ia_opt) {
-        // found IA
-        Option* tmp = ia_opt.get();
-        Option6IA* ia_req = dynamic_cast<Option6IA*>(tmp);
-        if (ia_req) {
-            boost::shared_ptr<Option6IA>
-                ia_rsp(new Option6IA(D6O_IA_NA, ia_req->getIAID()));
-            ia_rsp->setT1(HARDCODED_T1);
-            ia_rsp->setT2(HARDCODED_T2);
-            boost::shared_ptr<Option6IAAddr>
-                addr(new Option6IAAddr(D6O_IAADDR,
-                                       IOAddress(HARDCODED_LEASE),
-                                       HARDCODED_PREFERRED_LIFETIME,
-                                       HARDCODED_VALID_LIFETIME));
-            ia_rsp->addOption(addr);
-            answer->addOption(ia_rsp);
+
+    Subnet6Ptr subnet = getSubnet(question);
+    if (subnet) {
+        cout << "#### Selected subnet " << subnet->toText() << endl;
+    } else {
+        cout << "#### Failed to select a subnet" << endl;
+    }
+
+    // @todo: We should implement Option6Duid some day, but we can do without it
+    // just fine for now
+    DuidPtr duid;
+    OptionPtr opt_duid = question->getOption(D6O_CLIENTID);
+    if (opt_duid) {
+        duid = DuidPtr(new DUID(opt_duid->getData()));
+    }
+    if (duid) {
+        cout << "#### Processing request from client with duid=" << duid->toText() << endl;
+    } else {
+        cout << "#### Failed to find client-id :(" << endl;
+    }
+
+    for (Option::OptionCollection::iterator opt = question->options_.begin(); opt != question->options_.end(); ++opt) {
+        switch (opt->second->getType()) {
+        case D6O_IA_NA: {
+            OptionPtr answer_opt = handleIA_NA(subnet, duid, question, boost::dynamic_pointer_cast<Option6IA>(opt->second));
+            if (answer_opt) {
+                answer->addOption(answer_opt);
+            }
+            break;
+        }
+        default:
+            break;
         }
     }
 }
 
+OptionPtr Dhcpv6Srv::handleIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid, Pkt6Ptr question,
+                                 boost::shared_ptr<Option6IA> ia) {
+    if (!subnet) {
+        boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
+
+        ia_rsp->addOption(createStatusCode(STATUS_NoAddrsAvail, "Sorry, no subnet available."));
+        return (ia_rsp);
+    }
+
+    boost::shared_ptr<Option6IAAddr> hintOpt = boost::dynamic_pointer_cast<Option6IAAddr>(ia->getOption(D6O_IAADDR));
+
+    IOAddress hint("::");
+    cout << "#### Processing request IA_NA: iaid=" << ia->getIAID();
+    if (hintOpt) {
+        hint = hintOpt->getAddress();
+        cout << ", hint=" << hint.toText() << endl;
+    } else {
+        cout << ", no hint provided" << endl;
+    }
+
+    bool fake_allocation = false;
+    if (question->getType() == DHCPV6_SOLICIT) {
+        /// @todo: Check if we support rapid commit
+        fake_allocation = true;
+    }
+
+    Lease6Ptr lease = alloc_engine_->allocateAddress6(subnet, duid, ia->getIAID(),
+                                                      hint, fake_allocation);
+
+    boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
+
+    if (lease) {
+        cout << "#### Allocated lease:" << lease->addr_.toText() << endl;
+
+        ia_rsp->setT1(subnet->getT1());
+        ia_rsp->setT2(subnet->getT2());
+
+        boost::shared_ptr<Option6IAAddr>
+            addr(new Option6IAAddr(D6O_IAADDR,
+                                   lease->addr_,
+                                   lease->preferred_lft_,
+                                   lease->valid_lft_));
+        ia_rsp->addOption(addr);
+    } else {
+        cout << "#### Failed to allocate a lease";
+
+        ia_rsp->addOption(createStatusCode(STATUS_NoAddrsAvail, "Sorry, no address could be allocated."));
+    }
+    return (ia_rsp);
+}
+
 Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
+
     Pkt6Ptr advertise(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid()));
 
     copyDefaultOptions(solicit, advertise);
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index 1cb3236..b6daf49 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -19,6 +19,10 @@
 #include <dhcp/dhcp6.h>
 #include <dhcp/pkt6.h>
 #include <dhcp/option.h>
+#include <dhcp/subnet.h>
+#include <dhcp/duid.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/alloc_engine.h>
 #include <iostream>
 
 namespace isc {
@@ -147,6 +151,36 @@ protected:
     /// @param infRequest message received from client
     Pkt6Ptr processInfRequest(const Pkt6Ptr& infRequest);
 
+    /// @brief creates status-code option
+    ///
+    /// @param code status code value (see RFC3315)
+    /// @param text textual explanation (will be sent in status code option)
+    /// @return status-code option
+    OptionPtr createStatusCode(uint16_t code, const std::string& text);
+
+    /// @brief selects a subnet for a given client's packet
+    ///
+    /// @return selected subnet (or NULL if no suitable subnet was found)
+    isc::dhcp::Subnet6Ptr getSubnet(const Pkt6Ptr& question);
+
+    /// @brief processes IA_NA option (and assigns addresses if necessary)
+    ///
+    /// Generates response to IA_NA. This typically includes selecting (and
+    /// allocating a lease in case of REQUEST) a lease and creating
+    /// IAADDR option. In case of allocation failure, it may contain
+    /// status code option with non-zero status, denoting cause of the
+    /// allocation failure.
+    ///
+    /// @param subnet subnet the client is connected to
+    /// @param duid client's duid
+    /// @param question client's message (typically SOLICIT or REQUEST)
+    /// @param ia pointer to client's IA_NA option (client's request)
+    /// @return IA_NA option (server's response)
+    OptionPtr handleIA_NA(const isc::dhcp::Subnet6Ptr& subnet,
+                          const isc::dhcp::DuidPtr& duid,
+                          isc::dhcp::Pkt6Ptr question,
+                          boost::shared_ptr<Option6IA> ia);
+
     /// @brief Copies required options from client message to server answer
     ///
     /// Copies options that must appear in any server response (ADVERTISE, REPLY)
@@ -202,6 +236,12 @@ protected:
     /// server DUID (to be sent in server-identifier option)
     boost::shared_ptr<isc::dhcp::Option> serverid_;
 
+    /// @brief Allocation Engine
+    /// Pointer to the allocation engine that we are currently using
+    /// It must be a pointer, because we will support changing engines
+    /// during normal operation (e.g. to use different allocators)
+    AllocEngine* alloc_engine_;
+
     /// indicates if shutdown is in progress. Setting it to true will
     /// initiate server shutdown procedure.
     volatile bool shutdown_;
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index 43a1b04..3829d31 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -39,6 +39,10 @@ libb10_dhcpsrv_la_SOURCES += pool.cc pool.h
 libb10_dhcpsrv_la_SOURCES += subnet.cc subnet.h
 libb10_dhcpsrv_la_SOURCES += triplet.h
 libb10_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h
+
+# @todo: Remove this once MySQL LeaseMgr is merged
+libb10_dhcpsrv_la_SOURCES += tests/memfile_lease_mgr.cc tests/memfile_lease_mgr.h
+
 libb10_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
 libb10_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
 libb10_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
index ecaa652..1c2a11c 100644
--- a/src/lib/dhcp/iface_mgr.cc
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -247,6 +247,15 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
                 continue;
             }
 
+            // Bind link-local addresses only. Otherwise we bind several sockets
+            // on interfaces that have several global addresses. For examples
+            // with interface with 2 global addresses, we would bind 3 sockets
+            // (one for link-local and two for global). That would result in
+            // getting each message 3 times.
+            if (!addr->getAddress().to_v6().is_link_local()){
+                continue;
+            }
+
             sock = openSocket(iface->getName(), *addr, port);
             if (sock < 0) {
                 isc_throw(SocketConfigError, "failed to open unicast socket");



More information about the bind10-changes mailing list