Commit 5bde5c0d authored by Francis Dupont's avatar Francis Dupont

[4110a] Rebased previous code (checkpoint/not finished)

parent bf370fb3
......@@ -641,6 +641,12 @@ stopping IO between the DHCPv4 server and the DHCP_DDNS server. This is
probably due to a programmatic error is not likely to impact either server
upon restart. The reason for the failure is given within the message.
% DHCP4_SRV_DHCP4O6_ERROR error stopping IO with DHCPv4o6 during shutdown: %1
This error message indicates that during shutdown, an error occurred while
stopping IO between the DHCPv4 server and the DHCPv6o6 server. This is
probably due to a programmatic error is not likely to impact either server
upon restart. The reason for the failure is given within the message.
% DHCP4_STARTED Kea DHCPv4 server version %1 started
This informational message indicates that the DHCPv4 server has
processed all configuration information and is ready to process
......
......@@ -16,7 +16,10 @@
#include <dhcp/option_vendor.h>
#include <dhcp/option_string.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt4o6.h>
#include <dhcp/pkt6.h>
#include <dhcp/docsis3_option_defs.h>
#include <dhcp4/dhcp4to6_ipc.h>
#include <dhcp4/dhcp4_log.h>
#include <dhcp4/dhcp4_srv.h>
#include <dhcpsrv/addr_utilities.h>
......@@ -170,9 +173,33 @@ Dhcpv4Exchange::initResponse() {
resp_.reset(new Pkt4(resp_type, getQuery()->getTransid()));
copyDefaultFields();
copyDefaultOptions();
if (getQuery()->isDhcp4o6()) {
initResponse4o6();
}
}
}
void
Dhcpv4Exchange::initResponse4o6() {
Pkt4o6Ptr query = boost::dynamic_pointer_cast<Pkt4o6>(getQuery());
if (!query) {
return;
}
const Pkt6Ptr& query6 = query->getPkt6();
Pkt6Ptr resp6(new Pkt6(DHCPV6_DHCPV4_RESPONSE, query6->getTransid()));
// Don't add client-id or server-id
// But copy relay info
if (!query6->relay_info_.empty()) {
resp6->copyRelayInfo(query6);
}
// Copy interface and remote address
resp6->setIface(query6->getIface());
resp6->setIndex(query6->getIndex());
resp6->setRemoteAddr(query6->getRemoteAddr());
resp_.reset(new Pkt4o6(resp_, resp6));
}
void
Dhcpv4Exchange::copyDefaultFields() {
resp_->setIface(query_->getIface());
......@@ -357,6 +384,13 @@ Dhcpv4Srv::~Dhcpv4Srv() {
LOG_ERROR(dhcp4_logger, DHCP4_SRV_D2STOP_ERROR).arg(ex.what());
}
try {
Dhcp4to6Ipc::instance().close();
} catch(const std::exception& ex) {
// Highly unlikely, but lets Report it but go on
LOG_ERROR(dhcp4_logger, DHCP4_SRV_DHCP4O6_ERROR).arg(ex.what());
}
IfaceMgr::instance().closeSockets();
// The lease manager was instantiated during DHCPv4Srv configuration,
......@@ -376,6 +410,11 @@ Dhcpv4Srv::shutdown() {
isc::dhcp::Subnet4Ptr
Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query) const {
// DHCPv4-over-DHCPv6 is a special (and complex) case
if (query->isDhcp4o6()) {
return (selectSubnet4o6(query));
}
Subnet4Ptr subnet;
SubnetSelector selector;
......@@ -478,6 +517,140 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query) const {
return (subnet);
}
isc::dhcp::Subnet4Ptr
Dhcpv4Srv::selectSubnet4o6(const Pkt4Ptr& query) const {
// Here begin by the same thing than selectSubnet, i.e., the DHCPv4 part
Subnet4Ptr subnet;
SubnetSelector selector;
selector.ciaddr_ = query->getCiaddr();
selector.giaddr_ = query->getGiaddr();
selector.local_address_ = query->getLocalAddr();
selector.client_classes_ = query->classes_;
// moved selector.remote_address_ as it is IPv6
selector.iface_name_ = query->getIface();
// If the link-selection sub-option is present, extract its value.
// "The link-selection sub-option is used by any DHCP relay agent
// that desires to specify a subnet/link for a DHCP client request
// that it is relaying but needs the subnet/link specification to
// be different from the IP address the DHCP server should use
// when communicating with the relay agent." (RFC 3257)
//
// Try first Relay Agent Link Selection sub-option
OptionPtr rai = query->getOption(DHO_DHCP_AGENT_OPTIONS);
if (rai) {
OptionCustomPtr rai_custom =
boost::dynamic_pointer_cast<OptionCustom>(rai);
if (rai_custom) {
OptionPtr link_select =
rai_custom->getOption(RAI_OPTION_LINK_SELECTION);
if (link_select) {
OptionBuffer link_select_buf = link_select->getData();
if (link_select_buf.size() == sizeof(uint32_t)) {
selector.option_select_ =
IOAddress::fromBytes(AF_INET, &link_select_buf[0]);
}
}
}
} else {
// Or Subnet Selection option
OptionPtr sbnsel = query->getOption(DHO_SUBNET_SELECTION);
if (sbnsel) {
OptionCustomPtr oc =
boost::dynamic_pointer_cast<OptionCustom>(sbnsel);
if (oc) {
selector.option_select_ = oc->readAddress();
}
}
}
// Mark it as DHCPv4-over-DHCPv6
selector.dhcp4o6_ = true;
// Now the DHCPv6 part
selector.remote_address_ = query->getRemoteAddr();
selector.first_relay_linkaddr_ = IOAddress("::");
// Handle a DHCPv6 relayed query
Pkt4o6Ptr query4o6 = boost::dynamic_pointer_cast<Pkt4o6>(query);
if (!query4o6) {
isc_throw(Unexpected, "Can't get DHCP4o6 message");
}
const Pkt6Ptr& query6 = query4o6->getPkt6();
// Initialize fields specific to relayed messages.
if (query6 && !query6->relay_info_.empty()) {
BOOST_REVERSE_FOREACH(Pkt6::RelayInfo relay, query6->relay_info_) {
if (!relay.linkaddr_.isV6Zero() &&
!relay.linkaddr_.isV6LinkLocal()) {
selector.first_relay_linkaddr_ = relay.linkaddr_;
break;
}
}
selector.interface_id_ =
query6->getAnyRelayOption(D6O_INTERFACE_ID,
Pkt6::RELAY_GET_FIRST);
}
CfgMgr& cfgmgr = CfgMgr::instance();
subnet = cfgmgr.getCurrentCfg()->getCfgSubnets4()->selectSubnet(selector);
// Let's execute all callouts registered for subnet4_select
if (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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
DHCP4_HOOK_SUBNET4_SELECT_SKIP)
.arg(query->getLabel());
return (Subnet4Ptr());
}
/// @todo: Add support for DROP status
// Use whatever subnet was specified by the callout
callout_handle->getArgument("subnet4", subnet);
}
if (subnet) {
// Log at higher debug level that subnet has been found.
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC_DATA, DHCP4_SUBNET_SELECTED)
.arg(query->getLabel())
.arg(subnet->getID());
// Log detailed information about the selected subnet at the
// lower debug level.
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_SUBNET_DATA)
.arg(query->getLabel())
.arg(subnet->toText());
} else {
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL,
DHCP4_SUBNET_SELECTION_FAILED)
.arg(query->getLabel());
}
return (subnet);
}
Pkt4Ptr
Dhcpv4Srv::receivePacket(int timeout) {
return (IfaceMgr::instance().receive4(timeout));
......@@ -1638,7 +1811,8 @@ Dhcpv4Srv::adjustIfaceData(Dhcpv4Exchange& ex) {
// Instead we will need to use the address assigned to the interface
// on which the query has been received. In other cases, we will just
// use this address as a source address for the response.
if (local_addr.isV4Bcast()) {
// Do the same for DHCPv4-over-DHCPv6 exchanges.
if (local_addr.isV4Bcast() || query->isDhcp4o6()) {
SocketInfo sock_info = IfaceMgr::instance().getSocket(*query);
local_addr = sock_info.addr_;
}
......@@ -1670,6 +1844,12 @@ Dhcpv4Srv::adjustRemoteAddr(Dhcpv4Exchange& ex) {
Pkt4Ptr query = ex.getQuery();
Pkt4Ptr response = ex.getResponse();
// DHCPv4-over-DHCPv6 is simple
if (query->isDhcp4o6()) {
response->setRemoteAddr(query->getRemoteAddr());
return;
}
// The DHCPINFORM is slightly different than other messages in a sense
// that the server should always unicast the response to the ciaddr.
// It appears however that some clients don't set the ciaddr. We still
......@@ -2191,6 +2371,12 @@ Dhcpv4Srv::acceptDirectRequest(const Pkt4Ptr& pkt) const {
if (pkt->isRelayed()) {
return (true);
}
// Accept all DHCPv4-over-DHCPv6 messages.
if (pkt->isDhcp4o6()) {
return (true);
}
// The source address must not be zero for the DHCPINFORM message from
// the directly connected client because the server will not know where
// to respond if the ciaddr was not present.
......
......@@ -9,6 +9,8 @@
#include <dhcp/dhcp4.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt4o6.h>
#include <dhcp/pkt6.h>
#include <dhcp/option.h>
#include <dhcp/option_string.h>
#include <dhcp/option4_client_fqdn.h>
......@@ -81,6 +83,11 @@ public:
/// response is not initialized.
void initResponse();
/// @brief Initializes the DHCPv6 part of the response message
///
/// Called by initResponse() when the query is a DHCP4o6 message
void initResponse4o6();
/// @brief Returns the pointer to the query from the client.
Pkt4Ptr getQuery() const {
return (query_);
......@@ -713,6 +720,12 @@ protected:
/// @return selected subnet (or NULL if no suitable subnet was found)
isc::dhcp::Subnet4Ptr selectSubnet(const Pkt4Ptr& query) const;
/// @brief Selects a subnet for a given client's DHCP4o6 packet.
///
/// @param query client's message
/// @return selected subnet (or NULL if no suitable subnet was found)
isc::dhcp::Subnet4Ptr selectSubnet4o6(const Pkt4Ptr& query) const;
/// indicates if shutdown is in progress. Setting it to true will
/// initiate server shutdown procedure.
volatile bool shutdown_;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment