Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
d3c480a5
Commit
d3c480a5
authored
Jul 15, 2013
by
Tomek Mrugalski
🛰
Browse files
[2994] pkt4_receive, pkt4_send, subnet4_select implemented.
parent
56393640
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/dhcp4_log.h
View file @
d3c480a5
...
...
@@ -38,6 +38,9 @@ const int DBG_DHCP4_COMMAND = DBGLVL_COMMAND;
// Trace basic operations within the code.
const
int
DBG_DHCP4_BASIC
=
DBGLVL_TRACE_BASIC
;
// Trace hook related operations
const
int
DBG_DHCP4_HOOKS
=
DBGLVL_TRACE_BASIC
;
// Trace detailed operations, including errors raised when processing invalid
// packets. (These are not logged at severities of WARN or higher for fear
// that a set of deliberately invalid packets set to the server could overwhelm
...
...
src/bin/dhcp4/dhcp4_messages.mes
View file @
d3c480a5
...
...
@@ -60,6 +60,25 @@ This informational message is printed every time DHCPv4 server is started
and gives both the type and name of the database being used to store
lease and other information.
% DHCP4_HOOK_PACKET_RCVD_SKIP received DHCPv4 packet was dropped, because a callout set skip flag.
This debug message is printed when a callout installed on pkt4_receive
hook point sets skip flag. For this particular hook point, the setting
of the flag by a callout instructs the server to drop the packet.
% DHCP4_HOOK_PACKET_SEND_SKIP Prepared DHCPv6 response was not sent, because a callout set skip flag.
This debug message is printed when a callout installed on pkt4_send
hook point sets skip flag. For this particular hook point, the setting
of the flag by a callout instructs the server to drop the packet. This
effectively means that the client will not get any response, even though
the server processed client's request and acted on it (e.g. possibly
allocated a lease).
% DHCP4_HOOK_SUBNET4_SELECT_SKIP No subnet was selected, because a callout set skip flag.
This debug message is printed when a callout installed on subnet4_select
hook point sets a skip flag. It means that the server was told that no subnet
should be selected. This severely limits further processing - server will be only
able to offer global options. No addresses will be assigned.
% DHCP4_LEASE_ADVERT lease %1 advertised (client client-id %2, hwaddr %3)
This debug message indicates that the server successfully advertised
a lease. It is up to the client to choose one server out of othe advertised
...
...
src/bin/dhcp4/dhcp4_srv.cc
View file @
d3c480a5
...
...
@@ -30,6 +30,8 @@
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/utils.h>
#include <dhcpsrv/addr_utilities.h>
#include <hooks/hooks_manager.h>
#include <hooks/callout_handle.h>
#include <boost/algorithm/string/erase.hpp>
...
...
@@ -39,9 +41,30 @@
using
namespace
isc
;
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
dhcp
;
using
namespace
isc
::
hooks
;
using
namespace
isc
::
log
;
using
namespace
std
;
/// Structure that holds registered hook indexes
struct
Dhcp6Hooks
{
int
hook_index_pkt4_receive_
;
///< index for "pkt4_receive" hook point
int
hook_index_subnet4_select_
;
///< index for "subnet4_select" hook point
int
hook_index_pkt4_send_
;
///< index for "pkt4_send" hook point
/// Constructor that registers hook points for DHCPv6 engine
Dhcp6Hooks
()
{
hook_index_pkt4_receive_
=
HooksManager
::
registerHook
(
"pkt4_receive"
);
hook_index_subnet4_select_
=
HooksManager
::
registerHook
(
"subnet4_select"
);
hook_index_pkt4_send_
=
HooksManager
::
registerHook
(
"pkt4_send"
);
}
};
// Declare a Hooks object. As this is outside any function or method, it
// will be instantiated (and the constructor run) when the module is loaded.
// As a result, the hook indexes will be defined before any method in this
// module is called.
Dhcp6Hooks
Hooks
;
namespace
isc
{
namespace
dhcp
{
...
...
@@ -58,7 +81,9 @@ static const char* SERVER_ID_FILE = "b10-dhcp4-serverid";
// grants those options and a single, fixed, hardcoded lease.
Dhcpv4Srv
::
Dhcpv4Srv
(
uint16_t
port
,
const
char
*
dbconfig
,
const
bool
use_bcast
,
const
bool
direct_response_desired
)
{
const
bool
direct_response_desired
)
:
serverid_
(),
shutdown_
(
true
),
alloc_engine_
(),
hook_index_pkt4_receive_
(
-
1
),
hook_index_subnet4_select_
(
-
1
),
hook_index_pkt4_send_
(
-
1
)
{
LOG_DEBUG
(
dhcp4_logger
,
DBG_DHCP4_START
,
DHCP4_OPEN_SOCKET
).
arg
(
port
);
try
{
// First call to instance() will create IfaceMgr (it's a singleton)
...
...
@@ -103,6 +128,16 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig, const bool use_bcast,
// Instantiate allocation engine
alloc_engine_
.
reset
(
new
AllocEngine
(
AllocEngine
::
ALLOC_ITERATIVE
,
100
));
// Register hook points
hook_index_pkt4_receive_
=
Hooks
.
hook_index_pkt4_receive_
;
hook_index_subnet4_select_
=
Hooks
.
hook_index_subnet4_select_
;
hook_index_pkt4_send_
=
Hooks
.
hook_index_pkt4_send_
;
/// @todo call loadLibraries() when handling configuration changes
vector
<
string
>
libraries
;
// no libraries at this time
HooksManager
::
loadLibraries
(
libraries
);
}
catch
(
const
std
::
exception
&
e
)
{
LOG_ERROR
(
dhcp4_logger
,
DHCP4_SRV_CONSTRUCT_ERROR
).
arg
(
e
.
what
());
shutdown_
=
true
;
...
...
@@ -122,6 +157,14 @@ Dhcpv4Srv::shutdown() {
shutdown_
=
true
;
}
Pkt4Ptr
Dhcpv4Srv
::
receivePacket
(
int
timeout
)
{
return
(
IfaceMgr
::
instance
().
receive4
(
timeout
));
}
void
Dhcpv4Srv
::
sendPacket
(
const
Pkt4Ptr
&
packet
)
{
IfaceMgr
::
instance
().
send
(
packet
);
}
bool
Dhcpv4Srv
::
run
()
{
while
(
!
shutdown_
)
{
...
...
@@ -134,7 +177,7 @@ Dhcpv4Srv::run() {
Pkt4Ptr
rsp
;
try
{
query
=
IfaceMgr
::
instance
().
receive
4
(
timeout
);
query
=
receive
Packet
(
timeout
);
}
catch
(
const
std
::
exception
&
e
)
{
LOG_ERROR
(
dhcp4_logger
,
DHCP4_PACKET_RECEIVE_FAIL
).
arg
(
e
.
what
());
}
...
...
@@ -156,6 +199,31 @@ Dhcpv4Srv::run() {
LOG_DEBUG
(
dhcp4_logger
,
DBG_DHCP4_DETAIL_DATA
,
DHCP4_QUERY_DATA
)
.
arg
(
query
->
toText
());
// Let's execute all callouts registered for packet_received
if
(
HooksManager
::
getHooksManager
().
calloutsPresent
(
hook_index_pkt4_receive_
))
{
CalloutHandlePtr
callout_handle
=
getCalloutHandle
(
query
);
// Delete previously set arguments
callout_handle
->
deleteAllArguments
();
// Pass incoming packet as argument
callout_handle
->
setArgument
(
"query4"
,
query
);
// Call callouts
HooksManager
::
getHooksManager
().
callCallouts
(
hook_index_pkt4_receive_
,
*
callout_handle
);
// Callouts decided to skip the next processing step. The next
// processing step would to process the packet, so skip at this
// stage means drop.
if
(
callout_handle
->
getSkip
())
{
LOG_DEBUG
(
dhcp4_logger
,
DBG_DHCP4_HOOKS
,
DHCP4_HOOK_PACKET_RCVD_SKIP
);
continue
;
}
callout_handle
->
getArgument
(
"query4"
,
query
);
}
try
{
switch
(
query
->
getType
())
{
case
DHCPDISCOVER
:
...
...
@@ -220,13 +288,39 @@ Dhcpv4Srv::run() {
rsp
->
setIface
(
query
->
getIface
());
rsp
->
setIndex
(
query
->
getIndex
());
// Execute all callouts registered for packet6_send
if
(
HooksManager
::
getHooksManager
().
calloutsPresent
(
hook_index_pkt4_send_
))
{
CalloutHandlePtr
callout_handle
=
getCalloutHandle
(
query
);
// Delete all previous arguments
callout_handle
->
deleteAllArguments
();
// Clear skip flag if it was set in previous callouts
callout_handle
->
setSkip
(
false
);
// Set our response
callout_handle
->
setArgument
(
"response4"
,
rsp
);
// Call all installed callouts
HooksManager
::
getHooksManager
().
callCallouts
(
hook_index_pkt4_send_
,
*
callout_handle
);
// Callouts decided to skip the next processing step. The next
// processing step would to send the packet, so skip at this
// stage means "drop response".
if
(
callout_handle
->
getSkip
())
{
LOG_DEBUG
(
dhcp4_logger
,
DBG_DHCP4_HOOKS
,
DHCP4_HOOK_PACKET_SEND_SKIP
);
continue
;
}
}
LOG_DEBUG
(
dhcp4_logger
,
DBG_DHCP4_DETAIL_DATA
,
DHCP4_RESPONSE_DATA
)
.
arg
(
rsp
->
getType
()).
arg
(
rsp
->
toText
());
if
(
rsp
->
pack
())
{
try
{
IfaceMgr
::
instance
().
send
(
rsp
);
sendPacket
(
rsp
);
}
catch
(
const
std
::
exception
&
e
)
{
LOG_ERROR
(
dhcp4_logger
,
DHCP4_PACKET_SEND_FAIL
).
arg
(
e
.
what
());
}
...
...
@@ -782,17 +876,48 @@ Dhcpv4Srv::serverReceivedPacketName(uint8_t type) {
Subnet4Ptr
Dhcpv4Srv
::
selectSubnet
(
const
Pkt4Ptr
&
question
)
{
Subnet4Ptr
subnet
;
// Is this relayed message?
IOAddress
relay
=
question
->
getGiaddr
();
if
(
relay
.
toText
()
==
"0.0.0.0"
)
{
// Yes: Use relay address to select subnet
return
(
CfgMgr
::
instance
().
getSubnet4
(
relay
)
)
;
subnet
=
CfgMgr
::
instance
().
getSubnet4
(
relay
);
}
else
{
// No: Use client's address to select subnet
return
(
CfgMgr
::
instance
().
getSubnet4
(
question
->
getRemoteAddr
())
)
;
subnet
=
CfgMgr
::
instance
().
getSubnet4
(
question
->
getRemoteAddr
());
}
// Let's execute all callouts registered for packet_received
if
(
HooksManager
::
getHooksManager
().
calloutsPresent
(
hook_index_subnet4_select_
))
{
CalloutHandlePtr
callout_handle
=
getCalloutHandle
(
question
);
// We're reusing callout_handle from previous calls
callout_handle
->
deleteAllArguments
();
// Set new arguments
callout_handle
->
setArgument
(
"query4"
,
question
);
callout_handle
->
setArgument
(
"subnet4"
,
subnet
);
callout_handle
->
setArgument
(
"subnet4collection"
,
CfgMgr
::
instance
().
getSubnets4
());
// Call user (and server-side) callouts
HooksManager
::
getHooksManager
().
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 severly 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
);
}
void
...
...
@@ -820,5 +945,32 @@ Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
}
}
isc
::
hooks
::
CalloutHandlePtr
Dhcpv4Srv
::
getCalloutHandle
(
const
Pkt4Ptr
&
pkt
)
{
// This method returns a CalloutHandle for a given packet. It is guaranteed
// to return the same callout_handle (so user library contexts are
// preserved). This method works well if the server processes one packet
// at a time. Once the server architecture is extended to cover parallel
// packets processing (e.g. delayed-ack, some form of buffering etc.), this
// method has to be extended (e.g. store callouts in a map and use pkt as
// a key). Additional code would be required to release the callout handle
// once the server finished processing.
CalloutHandlePtr
callout_handle
;
static
Pkt4Ptr
old_pointer
;
if
(
!
callout_handle
||
old_pointer
!=
pkt
)
{
// This is the first packet or a different packet than previously
// passed to getCalloutHandle()
// Remember the pointer to this packet
old_pointer
=
pkt
;
callout_handle
=
HooksManager
::
getHooksManager
().
createCalloutHandle
();
}
return
(
callout_handle
);
}
}
// namespace dhcp
}
// namespace isc
src/bin/dhcp4/dhcp4_srv.h
View file @
d3c480a5
...
...
@@ -20,6 +20,7 @@
#include <dhcp/option.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/alloc_engine.h>
#include <hooks/callout_handle.h>
#include <boost/noncopyable.hpp>
...
...
@@ -296,6 +297,18 @@ protected:
/// initiate server shutdown procedure.
volatile
bool
shutdown_
;
/// @brief dummy wrapper around IfaceMgr::receive4
///
/// This method is useful for testing purposes, where its replacement
/// simulates reception of a packet. For that purpose it is protected.
virtual
Pkt4Ptr
receivePacket
(
int
timeout
);
/// @brief dummy wrapper around IfaceMgr::send()
///
/// This method is useful for testing purposes, where its replacement
/// simulates transmission of a packet. For that purpose it is protected.
virtual
void
sendPacket
(
const
Pkt4Ptr
&
pkt
);
private:
/// @brief Constructs netmask option based on subnet4
...
...
@@ -310,6 +323,17 @@ private:
/// during normal operation (e.g. to use different allocators)
boost
::
shared_ptr
<
AllocEngine
>
alloc_engine_
;
/// @brief returns callout handle for specified packet
///
/// @param pkt packet for which the handle should be returned
///
/// @return a callout handle to be used in hooks related to said packet
isc
::
hooks
::
CalloutHandlePtr
getCalloutHandle
(
const
Pkt4Ptr
&
pkt
);
/// Indexes for registered hook points
int
hook_index_pkt4_receive_
;
int
hook_index_subnet4_select_
;
int
hook_index_pkt4_send_
;
};
};
// namespace isc::dhcp
...
...
src/lib/dhcpsrv/cfgmgr.h
View file @
d3c480a5
...
...
@@ -201,6 +201,15 @@ public:
/// completely new?
void
deleteSubnets6
();
/// @brief returns const reference to all subnets6
///
/// This is used in a hook (subnet4_select), where the hook is able
/// to choose a different subnet. Server code has to offer a list
/// of possible choices (i.e. all subnets).
/// @return a pointer to const Subnet6 collection
const
Subnet4Collection
*
getSubnets4
()
{
return
(
&
subnets4_
);
}
/// @brief returns const reference to all subnets6
///
...
...
@@ -212,7 +221,6 @@ public:
return
(
&
subnets6_
);
}
/// @brief get IPv4 subnet by address
///
/// Finds a matching subnet, based on an address. This can be used
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment