mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 05:27:55 +00:00
[2982] Updates to address review comments
This commit is contained in:
parent
77c1644d0d
commit
cc508f6c28
@ -36,22 +36,22 @@
|
||||
* Regardless of your field of expertise, you are encouraged to visit
|
||||
* <a href="http://bind10.isc.org/">BIND10 webpage (http://bind10.isc.org)</a>
|
||||
*
|
||||
* @section hookDevelopersGuide
|
||||
* - @subpage hookIntroduction
|
||||
* - @subpage hookLanguages
|
||||
* - @subpage hookTerminology
|
||||
* - @subpage hookTutorial
|
||||
* - @subpage hookFrameworkFunctions
|
||||
* - @subpage hookCallouts
|
||||
* - @subpage hookExampleCallouts
|
||||
* - @subpage hookBuild
|
||||
* - @subpage hookConfiguration
|
||||
* - @subpage hookAdvancedTopics
|
||||
* - @subpage hookContextCreateDestroy
|
||||
* - @subpage hookCalloutRegistration
|
||||
* - @subpage hookMultipleLibraries
|
||||
* - @subpage hookInterLibraryData
|
||||
* - @subpage hookRegisterMultipleLibraries
|
||||
* @section hooksdgDevelopersGuide
|
||||
* - @subpage hooksdgIntroduction
|
||||
* - @subpage hooksdgLanguages
|
||||
* - @subpage hooksdgTerminology
|
||||
* - @subpage hooksdgTutorial
|
||||
* - @subpage hooksdgFrameworkFunctions
|
||||
* - @subpage hooksdgCallouts
|
||||
* - @subpage hooksdgExampleCallouts
|
||||
* - @subpage hooksdgBuild
|
||||
* - @subpage hooksdgConfiguration
|
||||
* - @subpage hooksdgAdvancedTopics
|
||||
* - @subpage hooksdgContextCreateDestroy
|
||||
* - @subpage hooksdgCalloutRegistration
|
||||
* - @subpage hooksdgMultipleLibraries
|
||||
* - @subpage hooksdgInterLibraryData
|
||||
* - @subpage hooksdgRegisterMultipleLibraries
|
||||
*
|
||||
* @section dnsMaintenanceGuide DNS Maintenance Guide
|
||||
* - Authoritative DNS (todo)
|
||||
|
@ -12,10 +12,14 @@
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
/**
|
||||
@page hookDevelopersGuide Hook Developer's Guide
|
||||
// Note: the prefix "hooksdg" to all labels is an abbreviation for "Hooks
|
||||
// Developer's Guide" and is used to prevent a clash with symbols in any
|
||||
// other Doxygen file.
|
||||
|
||||
@section hookIntroduction Introduction
|
||||
/**
|
||||
@page hooksdgDevelopersGuide Hook Developer's Guide
|
||||
|
||||
@section hooksdgIntroduction Introduction
|
||||
|
||||
Although the BIND 10 framework and its associated DNS and DHCP programs
|
||||
provide comprehensive functionality, there will be times when it does
|
||||
@ -31,7 +35,7 @@ understanding how it works will take a significant amount of time. In
|
||||
addition, despite the fact that its object-oriented design keeps the
|
||||
coupling between modules to a minimum, an inappropriate change to one
|
||||
part of the program during the extension could cause another to
|
||||
behave oddly or to stop working altogether, adding to development time.
|
||||
behave oddly or to stop working altogether.
|
||||
|
||||
- The change may need to be re-applied or re-written with every new
|
||||
version of BIND 10. As new functionality is added or bugs are fixed,
|
||||
@ -39,59 +43,59 @@ the code or algorithms in the core software may change - and may change
|
||||
significantly.
|
||||
|
||||
To overcome these problems, BIND 10 provides the "Hooks" interface -
|
||||
a defined interface for third-party or user-written code (for ease of
|
||||
reference in the rest of this document, such code will be referred to
|
||||
as "user-written code"). At specific points in its processing ("hook
|
||||
points") BIND 10 will make a call to this code. The call passes data
|
||||
that the user can examine and, if required, modify. BIND 10 used the
|
||||
modified code in the remainder of its processing.
|
||||
a defined interface for third-party or user-written code. (For ease of
|
||||
reference in the rest of this document, all such code will be referred
|
||||
to as "user code".) At specific points in its processing
|
||||
("hook points") BIND 10 will make a call to this code. The call passes
|
||||
data that the user code can examine and, if required, modify.
|
||||
BIND 10 uses the modified data in the remainder of its processing.
|
||||
|
||||
In order to minimise the interaction between BIND 10 and the
|
||||
In order to minimise the interaction between BIND 10 and the user
|
||||
code, the latter is built independently of BIND 10 in the form of
|
||||
a shared library (or libraries). These are made known to BIND 10
|
||||
through its configuration mechanism, and BIND 10 loads the library at
|
||||
run time. Libraries can be unloaded and reloaded as needed while BIND
|
||||
10 is running.
|
||||
|
||||
Use of a defined API and BIND 10 configuration mechanism means that as
|
||||
new versions of BIND 10 are released, there is no need to modify the
|
||||
user-written code. Unless there is a major change in an interface
|
||||
(which will be clearly documented) all that will be required is a
|
||||
rebuild of the libraries.
|
||||
Use of a defined API and the BIND 10 configuration mechanism means that
|
||||
as new versions of BIND 10 are released, there is no need to modify
|
||||
the user code. Unless there is a major change in an interface
|
||||
(which will be clearly documented), all that will be required is a rebuild
|
||||
of the libraries.
|
||||
|
||||
@note Although the defined interface should not change, the internals
|
||||
of some of the classes and structures referenced by the user-written
|
||||
code may alter. These changes will need to be reflected in the compiled
|
||||
version of the software, hence the need for a rebuild.
|
||||
of some of the classes and structures referenced by the user code may
|
||||
change between versions of BIND 10. These changes have to be reflected
|
||||
in the compiled version of the software, hence the need for a rebuild.
|
||||
|
||||
@subsection hookLanguages Languages
|
||||
@subsection hooksdgLanguages Languages
|
||||
|
||||
The core of BIND 10 is written in C++. While it is the intention to
|
||||
provide interfaces into user code written into other languages, the
|
||||
initial versions of the Hooks system requires that user code be written
|
||||
in C++. All examples in this guide are in that language.
|
||||
provide interfaces into user code written in other languages, the initial
|
||||
versions of the Hooks system requires that user code be written in C++.
|
||||
All examples in this guide are in that language.
|
||||
|
||||
@subsection hookTerminology Terminology
|
||||
@subsection hooksdgTerminology Terminology
|
||||
|
||||
In the remainder of this guide, the following terminology is used:
|
||||
|
||||
- Hook/Hook Point - used interchageably, this is a point in the code at
|
||||
which a call to user-written functions is made. Each hook has a name and
|
||||
each hook can have any number (including 0) of user-written functions
|
||||
which a call to user functions is made. Each hook has a name and
|
||||
each hook can have any number (including 0) of user functions
|
||||
attached to it.
|
||||
|
||||
- Callout - a user-written function called by the server at a hook
|
||||
- Callout - a user function called by the server at a hook
|
||||
point. This is so-named because the server "calls out" to the library
|
||||
to execute a user-written function.
|
||||
to execute a user function.
|
||||
|
||||
- Framework function - the functions that a user-written library needs to
|
||||
supply in order for the hooks framework for load and unload the library.
|
||||
- Framework function - the functions that a user library needs to
|
||||
supply in order for the hooks framework to load and unload the library.
|
||||
|
||||
- User code/user library - non-BIND 10 code that is compiled into a
|
||||
shared library and loaded by BIND 10 into its address space.
|
||||
|
||||
|
||||
@section hookTutorial Tutorial
|
||||
@section hooksdgTutorial Tutorial
|
||||
|
||||
To illustrate how to write code that integrates with BIND 10, we will
|
||||
use the following (rather contrived) example:
|
||||
@ -103,14 +107,14 @@ IPv4 addresses according to their hardware address, and want to log both
|
||||
the hardware address and allocated IP address for the clients of interest.
|
||||
|
||||
The following sections describe how to implement these requirements.
|
||||
The code presented here is not efficient and there are better ways
|
||||
of doing the task. The aim is to illustrate the main features of
|
||||
user-written hook code rather than provide an optimal solution.
|
||||
The code presented here is not efficient and there are better ways of
|
||||
doing the task. The aim however, is to illustrate the main features of
|
||||
user hook code not to provide an optimal solution.
|
||||
|
||||
|
||||
@subsection hookFrameworkFunctions Framework Functions
|
||||
@subsection hooksdgFrameworkFunctions Framework Functions
|
||||
|
||||
Loading an initializing a library holding user-written code makes use
|
||||
Loading and initializing a library holding user code makes use
|
||||
of three (user-supplied) functions:
|
||||
|
||||
- version - defines the version of BIND 10 code with which the user-library
|
||||
@ -118,10 +122,10 @@ is built
|
||||
- load - called when the library is loaded by the server.
|
||||
- unload - called when the library is unloaded by the server.
|
||||
|
||||
Of these, only "version" is mandatory, although our in out example, all three
|
||||
Of these, only "version" is mandatory, although our in our example, all three
|
||||
are used.
|
||||
|
||||
@subsubsection hookVersionFunction The "version" Function
|
||||
@subsubsection hooksdgVersionFunction The "version" Function
|
||||
|
||||
"version" is used by the hooks framework to check that the libraries
|
||||
it is loading are compatible with the version of BIND 10 being run.
|
||||
@ -129,14 +133,14 @@ Although the hooks system allows BIND 10 and user code to interface
|
||||
through a defined API, the relationship is somewhat tight in that the
|
||||
user code will depend on the internal structures of BIND 10. If these
|
||||
change - as they can between BIND 10 releases - and BIND 10 is run with
|
||||
a version of user-written code built against an earlier version of BIND
|
||||
a version of user code built against an earlier version of BIND
|
||||
10, a program crash could result.
|
||||
|
||||
To guard against this, the "version" function must be provided in
|
||||
every library. It returns a constant defined in the version of header
|
||||
files against which it was built. The hooks framework checks this for
|
||||
compatibility with the running version of BIND 10 before proceeding with
|
||||
the library load.
|
||||
To guard against this, the "version" function must be provided in every
|
||||
library. It returns a constant defined in header files of the version
|
||||
of BIND 10 against which it was built. The hooks framework checks this
|
||||
for compatibility with the running version of BIND 10 before loading
|
||||
the library.
|
||||
|
||||
In this tutorial, we'll put "version" in its own file, version.cc. The
|
||||
contents are:
|
||||
@ -155,10 +159,11 @@ int version() {
|
||||
};
|
||||
@endcode
|
||||
|
||||
The file "hooks/hooks.h" is specified relative to the BIND 10 libraries source
|
||||
directory - this is covered later in the section @ref hookBuild. It defines the
|
||||
symbol BIND10_HOOKS_VERSION, which has a value that changes on every release
|
||||
of BIND 10: this is the value that needs to be returned to the hooks framework.
|
||||
The file "hooks/hooks.h" is specified relative to the BIND 10 libraries
|
||||
source directory - this is covered later in the section @ref hooksdgBuild.
|
||||
It defines the symbol BIND10_HOOKS_VERSION, which has a value that changes
|
||||
on every release of BIND 10: this is the value that needs to be returned
|
||||
to the hooks framework.
|
||||
|
||||
A final point to note is that the definition of "version" is enclosed
|
||||
within 'extern "C"' braces. All functions accessed by the hooks
|
||||
@ -166,31 +171,36 @@ framework use C linkage, mainly to avoid the name mangling that
|
||||
accompanies use of the C++ compiler, but also to avoid issues related
|
||||
to namespaces.
|
||||
|
||||
@subsubsection hookLoadUnloadFunctions The "load" and "unload" Functions
|
||||
@subsubsection hooksdgLoadUnloadFunctions The "load" and "unload" Functions
|
||||
|
||||
As the names suggest, "load" is called when a library is loaded and
|
||||
"unload" called when it is unloaded. (It is always guaranteed that "load"
|
||||
is called: "unload" may not be called in some circumstances, e.g. if the
|
||||
system shuts down abnormally.) These functions are the places where any
|
||||
library-wide resources are allocated and deallocated. "load" is also
|
||||
the place where any callouts with non-standard names can be registered:
|
||||
this is covered further in the section @ref hookCalloutRegistration.
|
||||
"unload" called when it is unloaded. (It is always guaranteed that
|
||||
"load" is called: "unload" may not be called in some circumstances,
|
||||
e.g. if the system shuts down abnormally.) These functions are the
|
||||
places where any library-wide resources are allocated and deallocated.
|
||||
"load" is also the place where any callouts with non-standard names
|
||||
(names that are not hook point names) can be registered:
|
||||
this is covered further in the section @ref hooksdgCalloutRegistration.
|
||||
|
||||
The example does not make any use callouts with non-standard names. However,
|
||||
as our design requires that the log file be open while BIND 10 is active
|
||||
and the library loaded, we'll open the file in the "load" function and close
|
||||
it in "unload". We create two files, one for the file handle declaration:
|
||||
it in "unload".
|
||||
|
||||
We create two files, one for the file handle declaration:
|
||||
|
||||
@code
|
||||
// library_common.h
|
||||
|
||||
#ifndef LIBRARY_COMMON_H
|
||||
#define LIBRARY_COMMON_H
|
||||
|
||||
#include <fstream>
|
||||
|
||||
// "Interesting clients" log file handle declaration.
|
||||
extern std::fstream interesting;
|
||||
#endif
|
||||
|
||||
#endif // LIBRARY_COMMON_H
|
||||
@endcode
|
||||
|
||||
... and one to hold the "load" and "unload" functions:
|
||||
@ -227,37 +237,40 @@ Notes:
|
||||
outside of any function. This means it can be accessed by any function
|
||||
within the user library. For convenience, the definition is in the
|
||||
load_unload.cc file.
|
||||
- "load" is called with a LibraryHandle argument, used in the registration
|
||||
of functions. As no functions are being called in this example,
|
||||
the argument specification omits the variable name (whilst retaining the type)
|
||||
to avoid an "unused variable" compiler warning. (The LibraryHandle is
|
||||
discussed in the section @ref hookLibraryHandle.)
|
||||
- "load" is called with a LibraryHandle argument, this being used in
|
||||
the registration of functions. As no functions are being registered
|
||||
in this example, the argument specification omits the variable name
|
||||
(whilst retaining the type) to avoid an "unused variable" compiler
|
||||
warning. (The LibraryHandle and its use is discussed in the section
|
||||
@ref hooksdgLibraryHandle.)
|
||||
- In the current version of the hooks framework, it is not possible to pass
|
||||
any configuration information to the "load" function. The name of the log
|
||||
file must therefore be hard-coded as an absolute path name, or communicated
|
||||
to the user-written code by some other means.
|
||||
- "load" returns 0 on success and non-zero on error. The hooks framework
|
||||
file must therefore be hard-coded as an absolute path name or communicated
|
||||
to the user code by some other means.
|
||||
- "load" must 0 on success and non-zero on error. The hooks framework
|
||||
will abandon the loading of the library if "load" returns an error status.
|
||||
(In this example, "interesting" can be tested as a boolean value,
|
||||
returning "true" if the file opened successfully.)
|
||||
- "unload" closes the log file if it is open and is a no-op otherwise. As
|
||||
with "load", a zero value is returned on success and a non-zero value
|
||||
with "load", a zero value must be returned on success and a non-zero value
|
||||
on an error. The hooks framework will record a non-zero status return
|
||||
as an error in the current BIND 10 log but otherwise ignore it.
|
||||
- As before, the function definitions are enclosed in 'extern "C"' braces.
|
||||
|
||||
@subsection hookCallouts Callouts
|
||||
@subsection hooksdgCallouts Callouts
|
||||
|
||||
Having sorted out the framework, we now come to the functions that
|
||||
actually do something. These functions are known as "callouts" because
|
||||
the BIND 10 code "calls out" to them. Each BIND 10 server has a number
|
||||
of hooks to which callouts can be attached: the purpose of the hooks
|
||||
and the data passed to callouts is documented elsewhere.
|
||||
the BIND 10 code "calls out" to them. Each BIND 10 server has a number of
|
||||
hooks to which callouts can be attached: server-specific documentation
|
||||
describes in detail the points in the server at which the hooks are
|
||||
present together with the data passed to callouts attached to them.
|
||||
|
||||
Before we continue with the example, we'll discuss how arguments are
|
||||
passed to callouts and how information can be moved between them.
|
||||
passed to callouts and information is returned to the server. We will
|
||||
also discuss how information can be moved between callouts.
|
||||
|
||||
@subsubsection hookCalloutSignature The Callout Signature
|
||||
@subsubsection hooksdgCalloutSignature The Callout Signature
|
||||
|
||||
All callouts are declared with the signature:
|
||||
@code
|
||||
@ -279,7 +292,7 @@ log an error, specifying both the library and hook that generated it.
|
||||
Effectively the return status provides a quick way for a callout to log
|
||||
error information to the BIND 10 logging system.
|
||||
|
||||
@subsubsection hookArguments Callout Arguments
|
||||
@subsubsection hooksdgArguments Callout Arguments
|
||||
|
||||
The CalloutHandle object provides two methods to get and set the
|
||||
arguments passed to the callout. These methods are called (naturally
|
||||
@ -296,7 +309,7 @@ following code snippets.
|
||||
handle.setArgument("data_count", count);
|
||||
handle.setArgument("inpacket", pktptr);
|
||||
|
||||
// Call the hook code...
|
||||
// Call the callouts attached to the hook
|
||||
...
|
||||
|
||||
// Retrieve the modified values
|
||||
@ -342,15 +355,13 @@ be thrown if an attempt is made to retrieve it into a variable of type
|
||||
"const char*". (However, if an argument is set as a "const int", it can
|
||||
be retrieved into an "int".) The documentation of each hook point will
|
||||
detail the data type of each argument.
|
||||
|
||||
- Although all arguments can be modified, some altered values may not
|
||||
be read by the server. (These would be ones that the server considers
|
||||
"read-only".) Consult the documentation of each hook to see whether an
|
||||
argument can be used to transfer data back to the server.
|
||||
|
||||
- If a pointer to an object is passed to a callout (either a "raw"
|
||||
pointer, or a boost smart pointer (as in the example above), and the
|
||||
underlying object altered through that pointer, the change will be
|
||||
underlying object is altered through that pointer, the change will be
|
||||
reflected in the server even if no call is made to setArgument.
|
||||
|
||||
In all cases, consult the documentation for the particular hook to see whether
|
||||
@ -361,10 +372,54 @@ the server.
|
||||
- If you alter an argument, call CalloutHandle::setArgument to update the
|
||||
value in the CalloutHandle object.
|
||||
|
||||
@subsubsection hookCalloutContext Per-Request Context
|
||||
@subsubsection hooksdgSkipFlag The "Skip" Flag
|
||||
|
||||
When a to callouts attached to a hook returns, the server will usually continue
|
||||
its processing. However, a callout might have done something that means that
|
||||
the server should follow another path. Possible actions a server could take
|
||||
include:
|
||||
|
||||
- Skip the next stage of processing because the callout has already
|
||||
done it. For example, a hook is located just before the DHCP server
|
||||
allocates an address to the client. A callout may decide to allocate
|
||||
special addresses for certain clients, in which case it needs to tell
|
||||
the server not to allocate an address in this case.
|
||||
- Drop the packet and continue with the next request. A possible scenario
|
||||
is a DNS server where a callout inspects the source address of an incoming
|
||||
packet and compares it against a black list; if the address is on it,
|
||||
the callout notifies the server to drop the packet.
|
||||
|
||||
To handle these common cases, the CalloutHandle has a "skip" flag.
|
||||
This is set by a callout when it wishes the server to skip normal
|
||||
processing. It is set false by the hooks framework before callouts on a
|
||||
hook are called. If the flag is set on return, the server will take the
|
||||
"skip" action relevant for the hook.
|
||||
|
||||
The methods to get and set the "skip" flag are getSkip and setSkip. Their
|
||||
usage is intuitive:
|
||||
|
||||
@code
|
||||
// Get the current setting of the skip flag.
|
||||
bool skip = handle.getSkip();
|
||||
|
||||
// Do some processing...
|
||||
:
|
||||
if (lease_allocated) {
|
||||
// Flag the server to skip the next step of the processing as we
|
||||
// already have an address.
|
||||
handle.setSkip(true);
|
||||
}
|
||||
return;
|
||||
|
||||
@endcode
|
||||
|
||||
Like arguments, the "skip" flag is passed to all callouts on a hook. Callouts
|
||||
later in the list are able to examine (and modify) the settings of earlier ones.
|
||||
|
||||
@subsubsection hooksdgCalloutContext Per-Request Context
|
||||
|
||||
Although many of the BIND 10 modules can be characterised as handling
|
||||
a single packet - e.g. the DHCPv4 server receives a DISCOVER packet,
|
||||
singles packet - e.g. the DHCPv4 server receives a DISCOVER packet,
|
||||
processes it and responds with an OFFER, this is not true in all cases.
|
||||
The principal exception is the recursive DNS resolver: this receives a
|
||||
packet from a client but that packet may itself generate multiple packets
|
||||
@ -381,9 +436,8 @@ per-request basis.
|
||||
Context only exists only for the duration of the request: when a request
|
||||
is completed, the context is destroyed. A new request starts with no
|
||||
context information. Context is particularly useful in servers that may
|
||||
be processing multiple requests simultaneously: callouts are effectively
|
||||
attaching data to a request and that data follows the request around the
|
||||
system.
|
||||
be processing multiple requests simultaneously: callouts can effectively
|
||||
attach data to a request that follows the request around the system.
|
||||
|
||||
Context information is held as name/value pairs in the same way
|
||||
as arguments, being accessed by the pair of methods setContext and
|
||||
@ -391,11 +445,9 @@ getContext. They have the same restrictions as the setArgument and
|
||||
getArgument methods - the type of data retrieved from context must
|
||||
<B>exactly</B> match the type of the data set.
|
||||
|
||||
As the example in the tutorial uses per-request context, no separate
|
||||
example is given here.
|
||||
The example in the next section illustrates their use.
|
||||
|
||||
|
||||
@subsection hookExampleCallouts Example Callouts
|
||||
@subsection hooksdgExampleCallouts Example Callouts
|
||||
|
||||
Continuing with the tutorial, the requirements need us to retrieve the
|
||||
hardware address of the incoming packet, classify it, and write it,
|
||||
@ -409,14 +461,14 @@ We will do the classification here.
|
||||
|
||||
- v4_lease_write_post - called when the lease (an assignment of an IPv4
|
||||
address to a client for a fixed period of time) has been written to the
|
||||
database. It is passed two (constant) arguments, the query ("query")
|
||||
database. It is passed two arguments, the query ("query")
|
||||
and the response (called "reply"). This is the point at which the
|
||||
example code will write the hardware and IP addresses to the log file.
|
||||
|
||||
The standard for naming callouts is to give them the same name as
|
||||
the hook. If this is done, the callouts will be automatically found
|
||||
by the Hooks system (this is discussed further in section @ref
|
||||
hookCalloutRegistration). For our example, we will assume this is the
|
||||
hooksdgCalloutRegistration). For our example, we will assume this is the
|
||||
case, so the code for the first callout (used to classify the client's
|
||||
hardware address) is:
|
||||
|
||||
@ -435,7 +487,6 @@ using namespace std;
|
||||
extern "C" {
|
||||
|
||||
// This callout is called at the "pkt_rcvd" hook.
|
||||
|
||||
int pkt_rcvd(CalloutHandle& handle) {
|
||||
|
||||
// A pointer to the packet is passed to the callout via a "boost" smart
|
||||
@ -485,7 +536,6 @@ using namespace std;
|
||||
extern "C" {
|
||||
|
||||
// This callout is called at the "v4_lease_write_post" hook.
|
||||
|
||||
int v4_lease_write_post(CalloutHandle& handle) {
|
||||
|
||||
// Obtain the hardware address of the "interesting" client. We have to
|
||||
@ -495,10 +545,10 @@ int v4_lease_write_post(CalloutHandle& handle) {
|
||||
try (handle.getArgument("hwaddr", hwaddr) {
|
||||
|
||||
// getArgument didn't throw so the client is interesting. Get a pointer
|
||||
// to the reply. This is read-only so is passed through a smart pointer
|
||||
// const Pkt4 object. Note that the argument list also contains a
|
||||
// pointer to the query: we don't need to access that in this example.
|
||||
ConstPkt4Ptr reply;
|
||||
// to the reply. Note that the argument list for this hook also
|
||||
// contains a pointer to the query: we don't need to access that in this
|
||||
// example.
|
||||
Pkt4Ptr reply;
|
||||
handle.getArgument("reply", reply);
|
||||
|
||||
// Get the string form of the IP address.
|
||||
@ -523,13 +573,13 @@ int v4_lease_write_post(CalloutHandle& handle) {
|
||||
};
|
||||
@endcode
|
||||
|
||||
@subsection hookBuild Building the Library
|
||||
@subsection hooksdgBuild Building the Library
|
||||
|
||||
Building the code requires building a shareable library. This requires
|
||||
the the code be compiled as positition-independent code (using the
|
||||
compiler's -fpic switch) and linked as a shared library (with the linker's
|
||||
-shared switch). The build command also needs to point to the BIND 10 include
|
||||
directory and link in the appropriate libraries.
|
||||
compiler's "-fpic" switch) and linked as a shared library (with the
|
||||
linker's "-shared" switch). The build command also needs to point to
|
||||
the BIND 10 include directory and link in the appropriate libraries.
|
||||
|
||||
Assuming that BIND 10 has been installed in the default location, the
|
||||
command line needed to create the library using the Gnu C++ compiler on a
|
||||
@ -542,20 +592,18 @@ g++ -I /usr/include/bind10 -L /usr/lib/bind10 -fpic -shared -o example.so \
|
||||
@endcode
|
||||
|
||||
Notes:
|
||||
- the compilation command and switches required may vary depending on
|
||||
- The compilation command and switches required may vary depending on
|
||||
your operating system and compiler - consult the relevant documentation
|
||||
for details.
|
||||
- the values for the -I and -L switches depend on where you have installed
|
||||
BIND 10.
|
||||
- the list of libraries that need to be included in the command line
|
||||
- The values for the "-I" and "-L" switches depend on where you have
|
||||
installed BIND 10.
|
||||
- The list of libraries that need to be included in the command line
|
||||
depends on the functionality used by the hook code and the module to
|
||||
which they are attached (e.g. hook code for DNS will need to link against
|
||||
the libb10-dns++ library). Depending on operating system, you may also need
|
||||
to explicitly list libraries on which the BIND 10 libraries depend, e.g.
|
||||
in the command line above, libb10-exceptions depends on log4cplus, so it
|
||||
is possible that "-llog4cplus" may need to be appended to the command line.
|
||||
to explicitly list libraries on which the BIND 10 libraries depend.
|
||||
|
||||
@subsection hookConfiguration Configuring the Hook Library
|
||||
@subsection hooksdgConfiguration Configuring the Hook Library
|
||||
|
||||
The final step is to make the library known to BIND 10. All BIND 10 modules to
|
||||
which hooks can be added contain the "hook_library" element, and user
|
||||
@ -565,17 +613,17 @@ To add the example library (assumed to be in /usr/local/lib) to the DHCPv4
|
||||
module, the following bindctl commands must be executed:
|
||||
|
||||
@code
|
||||
> config add Dhcp4/hook_library
|
||||
> config set Dhcp4/hook_library[0]/name "/usr/local/lib/example.so"
|
||||
> config add Dhcp4/hook_libraries
|
||||
> config set Dhcp4/hook_libraries[0] "/usr/local/lib/example.so"
|
||||
> config commit
|
||||
@endcode
|
||||
|
||||
The DHCPv4 server will load the library and execute the callouts each time a
|
||||
request is received.
|
||||
|
||||
@section hookAdvancedTopics Advanced Topics
|
||||
@section hooksdgAdvancedTopics Advanced Topics
|
||||
|
||||
@subsection hookContextCreateDestroy Context Creation and Destruction
|
||||
@subsection hooksdgContextCreateDestroy Context Creation and Destruction
|
||||
|
||||
As well as the hooks defined by the server, the hooks framework defines
|
||||
two hooks of its own, "context_create" and "context_destroy". The first
|
||||
@ -585,14 +633,14 @@ to initialize per-request context. The second is called after all
|
||||
server-defined hooks have been processed, and is to allow a library to
|
||||
tidy up.
|
||||
|
||||
As an example, the v4_lease_write
|
||||
example above required that the code check for an exception being
|
||||
thrown when accessing the "hwaddr" context item in case it was not set.
|
||||
An alternative strategy would have been to provide a callout for the
|
||||
"context_create" hook and set the context item "hwaddr" to an empty
|
||||
string. Instead of needing to handle an exception, v4_lease_write would
|
||||
be guaranteed to get something when looking for the hwaddr item and so
|
||||
could write or not write the output depending on the value.
|
||||
As an example, the v4_lease_write example above required that the code
|
||||
check for an exception being thrown when accessing the "hwaddr" context
|
||||
item in case it was not set. An alternative strategy would have been to
|
||||
provide a callout for the "context_create" hook and set the context item
|
||||
"hwaddr" to an empty string. Instead of needing to handle an exception,
|
||||
v4_lease_write would be guaranteed to get something when looking for
|
||||
the hwaddr item and so could write or not write the output depending on
|
||||
the value.
|
||||
|
||||
In most cases, "context_destroy" is not needed as the Hooks system
|
||||
automatically deletes context. An example where it could be required
|
||||
@ -600,32 +648,143 @@ is where memory has been allocated by a callout during the processing
|
||||
of a request and a raw pointer to it stored in the context object. On
|
||||
destruction of the context, that memory will not be automatically
|
||||
released. Freeing in the memory in the "context_destroy callout will solve
|
||||
that problem. (Actually, when the context is destroyed, the destructor
|
||||
that problem.
|
||||
|
||||
Actually, when the context is destroyed, the destructor
|
||||
associated with any objects stored in it are run. Rather than point to
|
||||
allocated memory with a raw pointer, a better idea would be to point to
|
||||
it with a boost "smart" pointer and store that pointer in the context.
|
||||
When the context is destroyed, the smart pointer's destructor is run,
|
||||
which will automatically delete the pointed-to object.)
|
||||
which will automatically delete the pointed-to object.
|
||||
|
||||
These approaches are illustrated in the following examples.
|
||||
Here it is assumed that the hooks library is performing some form of
|
||||
security checking on the packet and needs to maintain information in
|
||||
a user-specified "SecurityInformation" object. (The details of this
|
||||
fictitious object are of no concern here.) The object is created in
|
||||
the context_create callout and used in both the pkt4_rcvd and the
|
||||
v4_lease_write_post callouts.
|
||||
|
||||
@code
|
||||
// Storing information in a "raw" pointer. Assume that the
|
||||
|
||||
#include <hooks/hooks.h>
|
||||
:
|
||||
|
||||
extern "C" {
|
||||
|
||||
// context_create callout - called when the request is created.
|
||||
int context_create(CalloutHandle& handle) {
|
||||
// Create the security information and store it in the context
|
||||
// for this packet.
|
||||
SecurityInformation* si = new SecurityInformation();
|
||||
handle.setContext("security_information", si);
|
||||
}
|
||||
|
||||
// Callouts that use the context
|
||||
int pktv_rcvd(CalloutHandle& handle) {
|
||||
// Retrieve the pointer to the SecurityInformation object
|
||||
SecurityInformation si;
|
||||
handle.getContext("security_information", si);
|
||||
:
|
||||
:
|
||||
// Set the security information
|
||||
si->setSomething(...);
|
||||
|
||||
// The pointed-to information has been updated but the pointer has not been
|
||||
// altered, so there is no need to call setContext() again.
|
||||
}
|
||||
|
||||
int v4_lease_write_post(CalloutHandle& handle) {
|
||||
// Retrieve the pointer to the SecurityInformation object
|
||||
SecurityInformation si;
|
||||
handle.getContext("security_information", si);
|
||||
:
|
||||
:
|
||||
// Retrieve security information
|
||||
bool active = si->getSomething(...);
|
||||
:
|
||||
}
|
||||
|
||||
// Context destruction. We need to delete the pointed-to SecurityInformation
|
||||
// object because we will lose the pointer to it when the CalloutHandle is
|
||||
// destroyed.
|
||||
int context_destroy(CalloutHandle& handle) {
|
||||
// Retrieve the pointer to the SecurityInformation object
|
||||
SecurityInformation si;
|
||||
handle.getContext("security_information", si);
|
||||
|
||||
// Delete the pointed-to memory.
|
||||
delete si;
|
||||
}
|
||||
@endcode
|
||||
|
||||
The requirement for the context_destroy callout can be eliminated if
|
||||
a Boost shared ptr is used to point to the allocated memory:
|
||||
|
||||
@code
|
||||
// Storing information in a "raw" pointer. Assume that the
|
||||
|
||||
#include <hooks/hooks.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
:
|
||||
|
||||
extern "C" {
|
||||
|
||||
// context_create callout - called when the request is created.
|
||||
|
||||
int context_create(CalloutHandle& handle) {
|
||||
// Create the security information and store it in the context for this
|
||||
// packet.
|
||||
boost::shared_ptr<SecurityInformation> si(new SecurityInformation());
|
||||
handle.setContext("security_information", si);
|
||||
}
|
||||
|
||||
// Other than the data type, a shared pointer has similar semantics to a "raw"
|
||||
// pointer. Only the code from pkt_rcvd is shown here.
|
||||
|
||||
int pktv_rcvd(CalloutHandle& handle) {
|
||||
// Retrieve the pointer to the SecurityInformation object
|
||||
boost::shared_ptr<SecurityInformation> si;
|
||||
handle.setContext("security_information", si);
|
||||
:
|
||||
:
|
||||
// Modify the security information
|
||||
si->setSomething(...);
|
||||
|
||||
// The pointed-to information has been updated but the pointer has not
|
||||
// altered, so theree is no need to reset the context.
|
||||
}
|
||||
|
||||
// No context_destroy callout is needed to delete the allocated
|
||||
// SecurityInformation object. When the CalloutHandle is destroyed, the shared
|
||||
// pointer object will be destroyed. If that is the last shared pointer to the
|
||||
// allocated memory, then it too will be deleted.
|
||||
@endcode
|
||||
|
||||
(Note that a Boost shared pointer - rather than any other Boost smart pointer -
|
||||
should be used, as the pointer objects are copied within the hooks framework and
|
||||
only shared pointers have the correct behavior for the copy operation.)
|
||||
|
||||
|
||||
@subsection hookCalloutRegistration Registering Callouts
|
||||
@subsection hooksdgCalloutRegistration Registering Callouts
|
||||
|
||||
As briefly mentioned in @ref hookExampleCallouts, the standard is for
|
||||
callouts in the user library to have the same name as the name of the hook
|
||||
to which they are being attached. This was followed in the tutorial, e.g.
|
||||
the callout that needed to be attached to the "pkt_rcvd" hook was named
|
||||
pkt_rcvd.
|
||||
As briefly mentioned in @ref hooksdgExampleCallouts, the standard is for
|
||||
callouts in the user library to have the same name as the name of the
|
||||
hook to which they are being attached. This convention was followed
|
||||
in the tutorial, e.g. the callout that needed to be attached to the
|
||||
"pkt_rcvd" hook was named pkt_rcvd.
|
||||
|
||||
The reason for this standard is that when the library is loaded, the
|
||||
hook framework automatically searches the library for functions with the
|
||||
same names as the server hooks. When it finds one, it attaches it to
|
||||
that hook point. This simplifies the loading process and bookkeeping
|
||||
required to create a library of callouts.
|
||||
The reason for this convention is that when the library is loaded, the
|
||||
hook framework automatically searches the library for functions with
|
||||
the same names as the server hooks. When it finds one, it attaches it
|
||||
to the appropriate hook point. This simplifies the loading process and
|
||||
bookkeeping required to create a library of callouts.
|
||||
|
||||
However, the hooks system is flexible in this area: callouts can have
|
||||
non-standard names, and multiple callouts can be registered on a hook.
|
||||
|
||||
@subsubsection hookLibraryHandle The LibraryHandle Object
|
||||
@subsubsection hooksdgLibraryHandle The LibraryHandle Object
|
||||
|
||||
The way into the part of the hooks framework that allows callout
|
||||
registration is through the LibraryHandle object. This was briefly
|
||||
@ -642,11 +801,11 @@ The LibraryHandle provides three methods to manipulate callouts:
|
||||
|
||||
The following sections cover some of the ways in which these can be used.
|
||||
|
||||
@subsubsection hookNonstandardCalloutNames Non-Standard Callout Names
|
||||
@subsubsection hooksdgNonstandardCalloutNames Non-Standard Callout Names
|
||||
|
||||
The example in the tutorial used standard names for the callouts. As noted
|
||||
above, it is possible to use non-standard names. Suppose, instead of the
|
||||
callout names "pkt_rcvd" and "v4_lease_write", we had named out callouts
|
||||
callout names "pkt_rcvd" and "v4_lease_write", we had named our callouts
|
||||
"classify" and "write_data". The hooks framework would not have registered
|
||||
these callouts, so we would have needed to do it ourself. The place to
|
||||
do this is the "load" framework function, and its code would have had to
|
||||
@ -670,7 +829,7 @@ It is possible for a library to contain callouts with both standard and
|
||||
non-standard names: ones with standard names will be registered automatically,
|
||||
ones with non-standard names need to be registered manually.
|
||||
|
||||
@subsubsection hookMultipleCallouts Multiple Callouts on a Hook
|
||||
@subsubsection hooksdgMultipleCallouts Multiple Callouts on a Hook
|
||||
|
||||
The BIND 10 hooks framework allows multiple callouts to be attached to
|
||||
a hook point. Although it is likely to be rare for user code to need to
|
||||
@ -684,16 +843,16 @@ LibraryHandle::registerCallout multiple times on the same hook, e.g.
|
||||
libhandle.registerCallout("pkt_rcvd", write_data);
|
||||
@endcode
|
||||
|
||||
The hooks framework will call the callouts in the order they are registered.
|
||||
The same CalloutHandle is passed between them, so any change made to the
|
||||
CalloutHandle's arguments or per-request context by the first is visible
|
||||
to the second.
|
||||
The hooks framework will call the callouts in the order they are
|
||||
registered. The same CalloutHandle is passed between them, so any
|
||||
change made to the CalloutHandle's arguments, "skip" flag, or per-request
|
||||
context by the first is visible to the second.
|
||||
|
||||
@subsubsection hookDynamicRegistration Dynamic Registration and Reregistration of Callouts
|
||||
@subsubsection hooksdgDynamicRegistration Dynamic Registration and Reregistration of Callouts
|
||||
|
||||
The previous sections have dealt with callouts being registered during
|
||||
the call to "load". The hooks framework is more flexible than that
|
||||
in that callouts and be registered and deregistered within a callout.
|
||||
in that callouts can be registered and deregistered within a callout.
|
||||
In fact, a callout is able to register or deregister itself, and a callout
|
||||
is able to be registered on a hook multiple times.
|
||||
|
||||
@ -716,7 +875,11 @@ int pkt_rcvd(CalloutHandle& handle) {
|
||||
|
||||
// Classify it.
|
||||
if (sum % 4 == 0) {
|
||||
// Interesting, register the callback to log the data.
|
||||
// Store the text form of the hardware address in the context to pass
|
||||
// to the next callout.
|
||||
handle.setContext("hwaddr", hwaddr_ptr->hwaddr_.toText());
|
||||
|
||||
// Register the callback to log the data.
|
||||
handle.getLibraryHandle().registerCallout("v4_lease_write", write_data);
|
||||
}
|
||||
|
||||
@ -758,7 +921,7 @@ int write_data(CalloutHandle& handle) {
|
||||
@endcode
|
||||
|
||||
Note that the above example used a non-standard name for the callout
|
||||
that wronte the data. Had the name been a standard one, it would have been
|
||||
that wrote the data. Had the name been a standard one, it would have been
|
||||
registered when the library was loaded and called for the first request,
|
||||
regardless of whether that was defined as "interesting". (Although as
|
||||
callouts with standard names are always registered before "load" gets called,
|
||||
@ -768,15 +931,14 @@ callout in the "load" function.)
|
||||
|
||||
@note Deregistration of a callout on the hook that is currently
|
||||
being called only takes effect when the server next calls the hook.
|
||||
To illustrate this, suppose the callouts attached to a hook are A,
|
||||
B and C (in that order), and during execution, A deregisters B and C
|
||||
and adds D. When callout A returns, B and C will still run. The next
|
||||
time the server calls the callouts attached to the hook, callouts
|
||||
A and D will run (in that order).
|
||||
To illustrate this, suppose the callouts attached to a hook are A, B and C
|
||||
(in that order), and during execution, A deregisters B and C and adds D.
|
||||
When callout A returns, B and C will still run. The next time the server
|
||||
calls the hook's callouts, A and D will run (in that order).
|
||||
|
||||
@subsection hookMultipleLibraries Multiple User Libraries
|
||||
@subsection hooksdgMultipleLibraries Multiple User Libraries
|
||||
|
||||
As alluded to in the section @ref hookConfiguration, BIND 10 can load
|
||||
As alluded to in the section @ref hooksdgConfiguration, BIND 10 can load
|
||||
multiple libraries. The libraries are loaded in the order specified in
|
||||
the configuration, and the callouts attached to the hooks in the order
|
||||
presented by the libraries.
|
||||
@ -818,7 +980,7 @@ It is stressed that the context for callouts associated with different
|
||||
libraries is entirely separate. For example, suppose "authorize" sets
|
||||
the CalloutHandle's context item "foo" to 2 and "logpkt" sets an item of
|
||||
the same name to the string "bar". When "check" accesses the context
|
||||
item "foo", it gets a value of 2: when "validate" accesses an item of
|
||||
item "foo", it gets a value of 2; when "validate" accesses an item of
|
||||
the same name, it gets the value "bar".
|
||||
|
||||
It is also stressed that all this context exists only for the life of the
|
||||
@ -831,7 +993,7 @@ without worrying about the presence of other libraries. Other libraries
|
||||
may be present, but will not affect the context values set by a library's
|
||||
callouts.
|
||||
|
||||
@subsection hookInterLibraryData Passing Data Between Libraries
|
||||
@subsection hooksdgInterLibraryData Passing Data Between Libraries
|
||||
|
||||
In rare cases, it is possible that one library may want to pass
|
||||
data to another. This can be done in a limited way by means of the
|
||||
@ -850,7 +1012,7 @@ the dollar symbol or percent sign. In this way there is no danger that
|
||||
a name will conflict with any existing or future BIND 10 argument names.
|
||||
|
||||
|
||||
@subsection hookRegisterMultipleLibraries Dynamic Callout Registration and Multiple Libraries
|
||||
@subsection hooksdgRegisterMultipleLibraries Dynamic Callout Registration and Multiple Libraries
|
||||
|
||||
On a particular hook, callouts are called in the order the libraries appear
|
||||
in the configuration and, within a library, in the order the callouts
|
||||
|
Loading…
x
Reference in New Issue
Block a user