Parcourir la source

[4097a] Introduce CfgOptionList and use it for the 3 append/getCfgOption() methods

Francis Dupont il y a 9 ans
Parent
commit
b925400a12
3 fichiers modifiés avec 97 ajouts et 45 suppressions
  1. 72 45
      src/bin/dhcp4/dhcp4_srv.cc
  2. 21 0
      src/bin/dhcp4/dhcp4_srv.h
  3. 4 0
      src/lib/dhcpsrv/cfg_option.h

+ 72 - 45
src/bin/dhcp4/dhcp4_srv.cc

@@ -822,6 +822,37 @@ Dhcpv4Srv::appendServerID(Dhcpv4Exchange& ex) {
 }
 
 void
+Dhcpv4Srv::buildCfgOptionList(Dhcpv4Exchange& ex) {
+    CfgOptionList& co_list = ex.getCfgOptionList();
+
+    // First subnet configured options
+    Subnet4Ptr subnet = ex.getContext()->subnet_;
+    if (subnet) {
+        co_list.push_back(subnet->getCfgOption());
+    }
+
+    // Each class in the incoming packet
+    const ClientClasses& classes = ex.getQuery()->getClasses();
+    for (ClientClasses::const_iterator cclass = classes.begin();
+         cclass != classes.end(); ++cclass) {
+        // Find the client class definition for this class
+        const ClientClassDefPtr& ccdef = CfgMgr::instance().getCurrentCfg()->
+            getClientClassDictionary()->findClass(*cclass);
+        if (!ccdef) {
+            // Not found: the class is not configured
+            LOG_DEBUG(options4_logger, DBG_DHCP4_BASIC, DHCP4_CLASS_UNCONFIGURED)
+                .arg(ex.getQuery()->getLabel())
+                .arg(*cclass);
+            continue;
+        }
+        co_list.push_back(ccdef->getCfgOption());
+    }
+
+    // Last global options
+    co_list.push_back(CfgMgr::instance().getCurrentCfg()->getCfgOption());
+}
+
+void
 Dhcpv4Srv::appendRequestedOptions(Dhcpv4Exchange& ex) {
     // Get the subnet relevant for the client. We will need it
     // to get the options associated with it.
@@ -854,36 +885,17 @@ Dhcpv4Srv::appendRequestedOptions(Dhcpv4Exchange& ex) {
     // to be returned to the client.
     for (std::vector<uint8_t>::const_iterator opt = requested_opts.begin();
          opt != requested_opts.end(); ++opt) {
+        // Add nothing when it is already there
         if (!resp->getOption(*opt)) {
-            OptionDescriptor desc = subnet->getCfgOption()->get("dhcp4", *opt);
-            if (desc.option_) {
-                resp->addOption(desc.option_);
-            }
-        }
-    }
-
-    // Process each class in the packet
-    const ClientClasses& classes = query->getClasses();
-    for (ClientClasses::const_iterator cclass = classes.begin();
-         cclass != classes.end(); ++cclass) {
-        // Find the client class definition for this class
-        const ClientClassDefPtr& ccdef = CfgMgr::instance().getCurrentCfg()->
-            getClientClassDictionary()->findClass(*cclass);
-        if (!ccdef) {
-            // Not found: the class is not configured
-            LOG_DEBUG(options4_logger, DBG_DHCP4_BASIC, DHCP4_CLASS_UNCONFIGURED)
-                .arg(query->getLabel())
-                .arg(*cclass);
-            continue;
-        }
-        // For each requested option code get the instance of the option
-        // in the class to be returned to the client.
-        for (std::vector<uint8_t>::const_iterator opt = requested_opts.begin();
-             opt != requested_opts.end(); ++opt) {
-            if (!resp->getOption(*opt)) {
-                OptionDescriptor desc = ccdef->getCfgOption()->get("dhcp4", *opt);
+            const CfgOptionList& co_list = ex.getCfgOptionList();
+            // Iterate on the configured option list
+            for (CfgOptionList::const_iterator copts = co_list.begin();
+                 copts != co_list.end(); ++copts) {
+                OptionDescriptor desc = (*copts)->get("dhcp4", *opt);
+                // Got it: add it and jump to the outer loop
                 if (desc.option_) {
                     resp->addOption(desc.option_);
+                    break;
                 }
             }
         }
@@ -932,11 +944,15 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
     for (std::vector<uint8_t>::const_iterator code = requested_opts.begin();
          code != requested_opts.end(); ++code) {
         if  (!vendor_rsp->getOption(*code)) {
-            OptionDescriptor desc = subnet->getCfgOption()->get(vendor_id,
-                                                                *code);
-            if (desc.option_) {
-                vendor_rsp->addOption(desc.option_);
-                added = true;
+            const CfgOptionList& co_list = ex.getCfgOptionList();
+            for (CfgOptionList::const_iterator copts = co_list.begin();
+                 copts != co_list.end(); ++copts) {
+                OptionDescriptor desc = (*copts)->get(vendor_id, *code);
+                if (desc.option_) {
+                    vendor_rsp->addOption(desc.option_);
+                    added = true;
+                    break;
+                }
             }
         }
 
@@ -973,10 +989,14 @@ Dhcpv4Srv::appendBasicOptions(Dhcpv4Exchange& ex) {
         OptionPtr opt = resp->getOption(required_options[i]);
         if (!opt) {
             // Check whether option has been configured.
-            OptionDescriptor desc = subnet->getCfgOption()->
-                get("dhcp4", required_options[i]);
-            if (desc.option_) {
-                resp->addOption(desc.option_);
+            const CfgOptionList& co_list = ex.getCfgOptionList();
+            for (CfgOptionList::const_iterator copts = co_list.begin();
+                 copts != co_list.end(); ++copts) {
+                OptionDescriptor desc = (*copts)->get("dhcp4", required_options[i]);
+                if (desc.option_) {
+                    resp->addOption(desc.option_);
+                    break;
+                }
             }
         }
     }
@@ -1617,6 +1637,7 @@ Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
 
     // Adding any other options makes sense only when we got the lease.
     if (!ex.getResponse()->getYiaddr().isV4Zero()) {
+        buildCfgOptionList(ex);
         appendRequestedOptions(ex);
         appendRequestedVendorOptions(ex);
         // There are a few basic options that we always want to
@@ -1672,6 +1693,7 @@ Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
 
     // Adding any other options makes sense only when we got the lease.
     if (!ex.getResponse()->getYiaddr().isV4Zero()) {
+        buildCfgOptionList(ex);
         appendRequestedOptions(ex);
         appendRequestedVendorOptions(ex);
         // There are a few basic options that we always want to
@@ -1951,6 +1973,7 @@ Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
 
     Pkt4Ptr ack = ex.getResponse();
 
+    buildCfgOptionList(ex);
     appendRequestedOptions(ex);
     appendRequestedVendorOptions(ex);
     appendBasicOptions(ex);
@@ -2380,15 +2403,19 @@ Dhcpv4Srv::vendorClassSpecificProcessing(const Dhcpv4Exchange& ex) {
 
         // Now try to set up file field in DHCPv4 packet. We will just copy
         // content of the boot-file option, which contains the same information.
-        OptionDescriptor desc = subnet->getCfgOption()->
-            get("dhcp4", DHO_BOOT_FILE_NAME);
-
-        if (desc.option_) {
-            boost::shared_ptr<OptionString> boot =
-                boost::dynamic_pointer_cast<OptionString>(desc.option_);
-            if (boot) {
-                std::string filename = boot->getValue();
-                rsp->setFile((const uint8_t*)filename.c_str(), filename.size());
+        const CfgOptionList& co_list = ex.getCfgOptionList();
+        for (CfgOptionList::const_iterator copts = co_list.begin();
+             copts != co_list.end(); ++copts) {
+            OptionDescriptor desc = (*copts)->get("dhcp4", DHO_BOOT_FILE_NAME);
+
+            if (desc.option_) {
+                boost::shared_ptr<OptionString> boot =
+                    boost::dynamic_pointer_cast<OptionString>(desc.option_);
+                if (boot) {
+                    std::string filename = boot->getValue();
+                    rsp->setFile((const uint8_t*)filename.c_str(), filename.size());
+                    break;
+                }
             }
         }
     }

+ 21 - 0
src/bin/dhcp4/dhcp4_srv.h

@@ -25,6 +25,7 @@
 #include <dhcpsrv/d2_client_mgr.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/alloc_engine.h>
+#include <dhcpsrv/cfg_option.h>
 #include <hooks/callout_handle.h>
 #include <dhcpsrv/daemon.h>
 
@@ -110,6 +111,16 @@ public:
         return (context_);
     }
 
+    /// @brief Returns the configured option list
+    CfgOptionList& getCfgOptionList() {
+        return (cfg_option_list_);
+    }
+
+    /// @brief Returns the configured option list
+    const CfgOptionList& getCfgOptionList() const {
+        return (cfg_option_list_);
+    }
+
 private:
 
     /// @brief Copies default parameters from client's to server's message
@@ -142,6 +153,8 @@ private:
     Pkt4Ptr resp_;
     /// @brief Context for use with allocation engine.
     AllocEngine::ClientContext4Ptr context_;
+    /// @brief Configured option list for appending otions.
+    CfgOptionList cfg_option_list_;
 };
 
 /// @brief Type representing the pointer to the @c Dhcpv4Exchange.
@@ -422,6 +435,14 @@ protected:
     /// @return DHCPACK to be sent to the client.
     Pkt4Ptr processInform(Pkt4Ptr& inform);
 
+    /// @brief Build the configured option list
+    ///
+    /// @note The configured option list is an *ordered* list of
+    /// @c CfgOption objects used to append options to the response.
+    ///
+    /// @param ex The exchange where the configured option list is cached
+    void buildCfgOptionList(Dhcpv4Exchange& ex);
+
     /// @brief Appends options requested by client.
     ///
     /// This method assigns options that were requested by client

+ 4 - 0
src/lib/dhcpsrv/cfg_option.h

@@ -27,6 +27,7 @@
 #include <stdint.h>
 #include <string>
 #include <set>
+#include <list>
 
 namespace isc {
 namespace dhcp {
@@ -407,6 +408,9 @@ typedef boost::shared_ptr<CfgOption> CfgOptionPtr;
 /// @brief Const pointer.
 typedef boost::shared_ptr<const CfgOption> ConstCfgOptionPtr;
 
+/// @brief Const pointer list.
+typedef std::list<ConstCfgOptionPtr> CfgOptionList;
+
 //@}
 
 }