ex.getResponse()->addOption(opt_srvid);
}
+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 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;
}
}
}
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;
+ }
}
}
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;
+ }
}
}
}
// 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
// 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
Pkt4Ptr ack = ex.getResponse();
+ buildCfgOptionList(ex);
appendRequestedOptions(ex);
appendRequestedVendorOptions(ex);
appendBasicOptions(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;
+ }
}
}
}
#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>
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
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.
/// @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