This debug message informs that incoming packet has been assigned to specified
class or classes. This is a normal behavior and indicates successful operation.
-% DHCP4_CLASS_PROCESSING_FAILED client class specific processing failed
-This debug message means that the server processing that is unique for each
-client class has reported a failure. The response packet will not be sent.
-
% DHCP4_CLIENT_NAME_PROC_FAIL failed to process the fqdn or hostname sent by a client: %1
This debug message is issued when the DHCP server was unable to process the
FQDN or Hostname option sent by a client. This is likely because the client's
A debug message indicating that the DHCPv4 server has received an
updated configuration from the Kea configuration system.
+% DHCP4_DISCOVER_CLASS_PROCESSING_FAILED client class specific processing failed for DHCPDISCOVER
+This debug message means that the server processing that is unique for each
+client class has reported a failure. The response packet will not be sent.
+
% DHCP4_DDNS_REQUEST_SEND_FAILED failed sending a request to kea-dhcp-ddns, error: %1, ncr: %2
This error message indicates that DHCP4 server attempted to send a DDNS
update request to the DHCP-DDNS server. This is most likely a configuration or
subnet, an action that severely limits further processing; the server
will be only able to offer global options - no addresses will be assigned.
+% DHCP4_INFORM_CLASS_PROCESSING_FAILED client class specific processing failed for DHCPINFORM
+This debug message means that the server processing that is unique for each
+client class has reported a failure. The response packet will not be sent.
+
% DHCP4_INIT_FAIL failed to initialize Kea server: %1
The server has failed to initialize. This may be because the configuration
was not successful, or it encountered any other critical error on startup.
hardware address is that a cloned virtual machine was not updated and
both clones use the same client-id.
+% DHCP4_REQUEST_CLASS_PROCESSING_FAILED client class specific processing failed for DHCPREQUEST
+This debug message means that the server processing that is unique for each
+client class has reported a failure. The response packet will not be sent.
+
% DHCP4_RESPONSE_DATA responding with packet type %1, data is <%2>
A debug message listing the data returned to the client.
namespace dhcp {
Dhcpv4Exchange::Dhcpv4Exchange(const AllocEnginePtr& alloc_engine,
- const Pkt4Ptr& query)
+ const Pkt4Ptr& query,
+ const Subnet4Ptr& subnet)
: alloc_engine_(alloc_engine), query_(query), resp_(),
context_(new AllocEngine::ClientContext4()) {
+
+ if (!alloc_engine_ || !query_) {
+ isc_throw(BadValue, "alloc_engine and query values must not"
+ " be NULL when creating an instance of the"
+ " Dhcpv4Exchange");
+ }
+
// Create response message.
initResponse();
// Select subnet for the query message.
- selectSubnet();
+ context_->subnet_ = subnet;
// Hardware address.
context_->hwaddr_ = query->getHWAddr();
// Client Identifier
}
}
-void
-Dhcpv4Exchange::selectSubnet() {
- context_->subnet_ = selectSubnet(query_);
-}
-
-Subnet4Ptr
-Dhcpv4Exchange::selectSubnet(const Pkt4Ptr& query) {
-
- Subnet4Ptr subnet;
-
- SubnetSelector selector;
- selector.ciaddr_ = query->getCiaddr();
- selector.giaddr_ = query->getGiaddr();
- selector.local_address_ = query->getLocalAddr();
- selector.remote_address_ = query->getRemoteAddr();
- selector.client_classes_ = query->classes_;
- selector.iface_name_ = query->getIface();
-
- CfgMgr& cfgmgr = CfgMgr::instance();
- subnet = cfgmgr.getCurrentCfg()->getCfgSubnets4()->selectSubnet(selector);
-
- // Let's execute all callouts registered for subnet4_select
- if (HooksManager::calloutsPresent(Hooks.hook_index_subnet4_select_)) {
- CalloutHandlePtr callout_handle = getCalloutHandle(query);
-
- // We're reusing callout_handle from previous calls
- callout_handle->deleteAllArguments();
-
- // Set new arguments
- callout_handle->setArgument("query4", query);
- callout_handle->setArgument("subnet4", subnet);
- callout_handle->setArgument("subnet4collection",
- cfgmgr.getCurrentCfg()->
- getCfgSubnets4()->getAll());
-
- // Call user (and server-side) callouts
- HooksManager::callCallouts(Hooks.hook_index_subnet4_select_,
- *callout_handle);
-
- // Callouts decided to skip this step. This means that no subnet
- // will be selected. Packet processing will continue, but it will
- // be severely limited (i.e. only global options will be assigned)
- if (callout_handle->getSkip()) {
- LOG_DEBUG(dhcp4_logger, DBG_DHCP4_HOOKS,
- DHCP4_HOOK_SUBNET4_SELECT_SKIP);
- return (Subnet4Ptr());
- }
-
- // Use whatever subnet was specified by the callout
- callout_handle->getArgument("subnet4", subnet);
- }
-
- return (subnet);
-}
-
const std::string Dhcpv4Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const bool use_bcast,
}
isc::dhcp::Subnet4Ptr
-Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) {
- return (Dhcpv4Exchange::selectSubnet(question));
+Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query, const bool run_hooks) const {
+
+ Subnet4Ptr subnet;
+
+ SubnetSelector selector;
+ selector.ciaddr_ = query->getCiaddr();
+ selector.giaddr_ = query->getGiaddr();
+ selector.local_address_ = query->getLocalAddr();
+ selector.remote_address_ = query->getRemoteAddr();
+ selector.client_classes_ = query->classes_;
+ selector.iface_name_ = query->getIface();
+
+ CfgMgr& cfgmgr = CfgMgr::instance();
+ subnet = cfgmgr.getCurrentCfg()->getCfgSubnets4()->selectSubnet(selector);
+
+ // Let's execute all callouts registered for subnet4_select
+ if (run_hooks && HooksManager::calloutsPresent(hook_index_subnet4_select_)) {
+ CalloutHandlePtr callout_handle = getCalloutHandle(query);
+
+ // We're reusing callout_handle from previous calls
+ callout_handle->deleteAllArguments();
+
+ // Set new arguments
+ callout_handle->setArgument("query4", query);
+ callout_handle->setArgument("subnet4", subnet);
+ callout_handle->setArgument("subnet4collection",
+ cfgmgr.getCurrentCfg()->
+ getCfgSubnets4()->getAll());
+
+ // Call user (and server-side) callouts
+ HooksManager::callCallouts(hook_index_subnet4_select_,
+ *callout_handle);
+
+ // Callouts decided to skip this step. This means that no subnet
+ // will be selected. Packet processing will continue, but it will
+ // be severely limited (i.e. only global options will be assigned)
+ if (callout_handle->getSkip()) {
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_HOOKS,
+ DHCP4_HOOK_SUBNET4_SELECT_SKIP);
+ return (Subnet4Ptr());
+ }
+
+ // Use whatever subnet was specified by the callout
+ callout_handle->getArgument("subnet4", subnet);
+ }
+
+ return (subnet);
}
Pkt4Ptr
continue;
}
- // Let's do class specific processing. This is done before
- // pkt4_send.
- //
- /// @todo: decide whether we want to add a new hook point for
- /// doing class specific processing.
- if (!classSpecificProcessing(query, rsp)) {
- /// @todo add more verbosity here
- LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_CLASS_PROCESSING_FAILED);
-
- continue;
- }
// Specifies if server should do the packing
bool skip_pack = false;
Pkt4Ptr
Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
- Dhcpv4Exchange ex(alloc_engine_, discover);
+ sanityCheck(discover, FORBIDDEN);
- sanityCheck(ex, FORBIDDEN);
+ Dhcpv4Exchange ex(alloc_engine_, discover, selectSubnet(discover));
copyDefaultFields(ex);
appendDefaultOptions(ex);
appendServerID(ex);
+ /// @todo: decide whether we want to add a new hook point for
+ /// doing class specific processing.
+ if (!classSpecificProcessing(ex)) {
+ /// @todo add more verbosity here
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_DISCOVER_CLASS_PROCESSING_FAILED);
+ }
+
return (ex.getResponse());
}
Pkt4Ptr
Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
- Dhcpv4Exchange ex(alloc_engine_, request);
-
/// @todo Uncomment this (see ticket #3116)
- /// sanityCheck(ex, MANDATORY);
+ /// sanityCheck(request, MANDATORY);
+
+ Dhcpv4Exchange ex(alloc_engine_, request, selectSubnet(request));
copyDefaultFields(ex);
appendDefaultOptions(ex);
appendServerID(ex);
+ /// @todo: decide whether we want to add a new hook point for
+ /// doing class specific processing.
+ if (!classSpecificProcessing(ex)) {
+ /// @todo add more verbosity here
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_REQUEST_CLASS_PROCESSING_FAILED);
+ }
+
return (ex.getResponse());
}
Pkt4Ptr
Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
- Dhcpv4Exchange ex(alloc_engine_, inform);
-
// DHCPINFORM MUST not include server identifier.
- sanityCheck(ex, FORBIDDEN);
+ sanityCheck(inform, FORBIDDEN);
+
+ Dhcpv4Exchange ex(alloc_engine_, inform, selectSubnet(inform));
Pkt4Ptr ack = ex.getResponse();
// The DHCPACK must contain server id.
appendServerID(ex);
+
+ /// @todo: decide whether we want to add a new hook point for
+ /// doing class specific processing.
+ if (!classSpecificProcessing(ex)) {
+ /// @todo add more verbosity here
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_INFORM_CLASS_PROCESSING_FAILED);
+ }
+
return (ex.getResponse());
}
return (false);
}
return ((pkt->getLocalAddr() != IOAddress::IPV4_BCAST_ADDRESS()
- || Dhcpv4Exchange::selectSubnet(pkt)));
+ || selectSubnet(pkt, false)));
}
bool
}
void
-Dhcpv4Srv::sanityCheck(const Dhcpv4Exchange& ex, RequirementLevel serverid) {
- OptionPtr server_id = ex.getQuery()->getOption(DHO_DHCP_SERVER_IDENTIFIER);
+Dhcpv4Srv::sanityCheck(const Pkt4Ptr& query, RequirementLevel serverid) {
+ OptionPtr server_id = query->getOption(DHO_DHCP_SERVER_IDENTIFIER);
switch (serverid) {
case FORBIDDEN:
if (server_id) {
isc_throw(RFCViolation, "Server-id option was not expected, but "
<< "received in "
- << serverReceivedPacketName(ex.getQuery()->getType()));
+ << serverReceivedPacketName(query->getType()));
}
break;
if (!server_id) {
isc_throw(RFCViolation, "Server-id option was expected, but not "
" received in message "
- << serverReceivedPacketName(ex.getQuery()->getType()));
+ << serverReceivedPacketName(query->getType()));
}
break;
}
// If there is HWAddress set and it is non-empty, then we're good
- if (ex.getQuery()->getHWAddr() && !ex.getQuery()->getHWAddr()->hwaddr_.empty()) {
+ if (query->getHWAddr() && !query->getHWAddr()->hwaddr_.empty()) {
return;
}
// There has to be something to uniquely identify the client:
// either non-zero MAC address or client-id option present (or both)
- OptionPtr client_id = ex.getQuery()->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
+ OptionPtr client_id = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
// If there's no client-id (or a useless one is provided, i.e. 0 length)
if (!client_id || client_id->len() == client_id->getHeaderLen()) {
isc_throw(RFCViolation, "Missing or useless client-id and no HW address "
" provided in message "
- << serverReceivedPacketName(ex.getQuery()->getType()));
+ << serverReceivedPacketName(query->getType()));
}
}
}
}
-bool Dhcpv4Srv::classSpecificProcessing(const Pkt4Ptr& query, const Pkt4Ptr& rsp) {
+bool
+Dhcpv4Srv::classSpecificProcessing(const Dhcpv4Exchange& ex) {
- Subnet4Ptr subnet = Dhcpv4Exchange::selectSubnet(query);
- if (!subnet) {
+ Subnet4Ptr subnet = ex.getContext()->subnet_;
+ Pkt4Ptr query = ex.getQuery();
+ Pkt4Ptr rsp = ex.getResponse();
+
+ // If any of those is missing, there is nothing to do.
+ if (!subnet || !query || !rsp) {
return (true);
}
/// @param alloc_engine Pointer to the instance of the Allocation Engine
/// used by the server.
/// @param query Pointer to the client message.
- Dhcpv4Exchange(const AllocEnginePtr& alloc_engine, const Pkt4Ptr& query);
+ /// @param subnet Pointer to the subnet to which the client belongs.
+ Dhcpv4Exchange(const AllocEnginePtr& alloc_engine, const Pkt4Ptr& query,
+ const Subnet4Ptr& subnet);
/// @brief Initializes the instance of the response message.
///
/// response is not initialized.
void initResponse();
- /// @brief Selects the subnet for the message processing.
- ///
- /// The pointer to the selected subnet is stored in the @c ClientContext4
- /// structure.
- void selectSubnet();
-
- /// @brief Selects the subnet for the message processing.
- ///
- /// @todo This variant of the @c selectSubnet method is static and public so
- /// as it may be invoked by the @c Dhcpv4Srv object. This is temporary solution
- /// and the function will go away once the server code fully supports the use
- /// of this class and it obtains the subnet from the context returned by the
- /// @c getContext method.
- ///
- /// @param query Pointer to the client's message.
- /// @return Pointer to the selected subnet or NULL if no suitable subnet
- /// has been found.
- static Subnet4Ptr selectSubnet(const Pkt4Ptr& query);
-
/// @brief Returns the pointer to the query from the client.
Pkt4Ptr getQuery() const {
return (query_);
/// Checks if mandatory option is really there, that forbidden option
/// is not there, and that client-id or server-id appears only once.
///
- /// @param ex DHCPv4 exchange holding the client's message to be checked.
+ /// @param query Pointer to the client's message.
/// @param serverid expectation regarding server-id option
/// @throw RFCViolation if any issues are detected
- static void sanityCheck(const Dhcpv4Exchange& ex, RequirementLevel serverid);
+ static void sanityCheck(const Pkt4Ptr& query, RequirementLevel serverid);
/// @brief Processes incoming DISCOVER and returns response.
///
/// @brief Selects a subnet for a given client's packet.
///
- /// @param question client's message
+ /// The @c run_hooks parameters controls whether the method should run
+ /// installed hooks for subnet selection. Disabling it is useful in
+ /// cases when the server should sanity check the client's packet before
+ /// the actual processing. If the sanity check fails, the packet can
+ /// be discarded.
+ ///
+ /// @param query client's message
+ /// @param run_hooks A boolean value which specifies if the method should
+ /// run installed hooks after selecting the subnet (if true). The default
+ /// value is true.
/// @return selected subnet (or NULL if no suitable subnet was found)
- static isc::dhcp::Subnet4Ptr selectSubnet(const Pkt4Ptr& question);
+ isc::dhcp::Subnet4Ptr selectSubnet(const Pkt4Ptr& query,
+ const bool run_hooks = true) const;
/// indicates if shutdown is in progress. Setting it to true will
/// initiate server shutdown procedure.
/// @brief Performs packet processing specific to a class
///
- /// This processing is a likely candidate to be pushed into hooks.
+ /// If the selected subnet, query or response in the @c ex object is NULL
+ /// this method returns immediately and returns true.
///
- /// @param query incoming client's packet
- /// @param rsp server's response
+ /// @note This processing is a likely candidate to be pushed into hooks.
+ ///
+ /// @param ex The exchange holding both the client's message and the
+ /// server's response.
/// @return true if successful, false otherwise (will prevent sending response)
- bool classSpecificProcessing(const Pkt4Ptr& query, const Pkt4Ptr& rsp);
+ bool classSpecificProcessing(const Dhcpv4Exchange& ex);
/// @brief Allocation Engine.
/// Pointer to the allocation engine that we are currently using