NAME
hhook
,
hhook_head_register
,
hhook_head_deregister
,
hhook_head_deregister_lookup
,
hhook_run_hooks
,
HHOOKS_RUN_IF
,
HHOOKS_RUN_LOOKUP_IF
—
Helper Hook Framework
SYNOPSIS
#include
<sys/hhook.h>
typedef int
(*hhook_func_t)
(int32_t
hhook_type, int32_t
hhook_id, void
*udata, void
*ctx_data, void
*hdata, struct osd
*hosd);
int
hhook_head_register
(int32_t
hhook_type, int32_t
hhook_id, struct
hhook_head **hhh,
uint32_t flags);
int
hhook_head_deregister
(struct
hhook_head *hhh);
int
hhook_head_deregister_lookup
(int32_t
hhook_type, int32_t
hhook_id);
void
hhook_run_hooks
(struct
hhook_head *hhh, void
*ctx_data, struct osd
*hosd);
HHOOKS_RUN_IF
(hhh,
ctx_data,
hosd);
HHOOKS_RUN_LOOKUP_IF
(hhook_type,
hhook_id,
ctx_data,
hosd);
DESCRIPTION
hhook
provides a framework for managing and running
arbitrary hook functions at defined hook points within the kernel. The KPI was
inspired by pfil(9), and in many respects can be thought of as a more
generic superset of pfil.
The khelp(9) and hhook
frameworks are
tightly integrated. Khelp is responsible for registering and deregistering
Khelp module hook functions with hhook
points. The
KPI functions used by
khelp(9) to do this are not documented here as they are not relevant
to consumers wishing to instantiate hook points.
Information for Khelp Module Implementors
Khelp modules indirectly interact with
hhook
by defining appropriate hook functions for
insertion into hook points. Hook functions must conform to the
hhook_func_t function pointer declaration outlined in
the SYNOPSIS.
The hhook_type and
hhook_id arguments identify the hook point which has
called into the hook function. These are useful when a single hook function
is registered for multiple hook points and wants to know which hook point
has called into it.
<sys/hhook.h>
lists
available hhook_type defines and subsystems which
export hook points are responsible for defining the
hhook_id value in appropriate header files.
The udata argument will be passed to the hook function if it was specified in the struct hookinfo at hook registration time.
The ctx_data argument contains context specific data from the hook point call site. The data type passed is subsystem dependent.
The hdata argument is a pointer to the persistent per-object storage allocated for use by the module if required. The pointer will only ever be NULL if the module did not request per-object storage.
The hosd argument can be
used with the khelp(9) framework's
khelp_get_osd
()
function to access data belonging to a different Khelp module.
Khelp modules instruct the Khelp framework to register their hook
functions with hhook
points by creating a
struct hookinfo per hook point, which contains the
following members:
struct hookinfo { hhook_func_t hook_func; struct helper *hook_helper; void *hook_udata; int32_t hook_id; int32_t hook_type; };
Khelp modules are responsible for setting all members of the struct except hook_helper which is handled by the Khelp framework.
Creating and Managing Hook Points
Kernel subsystems that wish to provide
hhook
points typically need to make four and
possibly five key changes to their implementation:
- Define a list of hhook_id mappings in an appropriate subsystem header.
- Register each hook point with the
hhook_head_register
() function during initialisation of the subsystem. - Select or create a standardised data type to pass to hook functions as contextual data.
- Add a call to
HHOOKS_RUN_IF
() orHHOOKS_RUN_IF_LOOKUP
() at the point in the subsystem's code where the hook point should be executed. - If the subsystem can be dynamically added/removed at runtime, each hook
point registered with the
hhook_head_register
() function when the subsystem was initialised needs to be deregistered with thehhook_head_deregister
() orhhook_head_deregister_lookup
() functions when the subsystem is being deinitialised prior to removal.
The
hhook_head_register
()
function registers a hook point with the hhook
framework. The hook_type argument defines the high
level type for the hook point. Valid types are defined in
<sys/hhook.h>
and new types
should be added as required. The hook_id argument
specifies a unique, subsystem specific identifier for the hook point. The
hhh argument will, if not NULL, be used to store a
reference to the struct hhook_head created as part of
the registration process. Subsystems will generally want to store a local
copy of the struct hhook_head so that they can use the
HHOOKS_RUN_IF
() macro to instantiate hook points.
The HHOOK_WAITOK flag may be passed in via the flags
argument if malloc(9) is allowed to sleep waiting for memory to become
available. If the hook point is within a virtualised subsystem (e.g. the
network stack), the HHOOK_HEADISINVNET flag should be passed in via the
flags argument so that the struct
hhook_head created during the registration process will be added to a
virtualised list.
The
hhook_head_deregister
()
function deregisters a previously registered hook point from the
hhook
framework. The hhh
argument is the pointer to the struct hhook_head
returned by
hhoook_head_register
()
when the hook point was registered.
The
hhook_head_deregister_lookup
()
function can be used instead of
hhook_head_deregister
() in situations where the
caller does not have a cached copy of the struct
hhook_head and wants to deregister a hook point using the appropriate
hook_type and hook_id
identifiers instead.
The
hhook_run_hooks
()
function should normally not be called directly and should instead be called
indirectly via the HHOOKS_RUN_IF
() macro. However,
there may be circumstances where it is preferable to call the function
directly, and so it is documented here for completeness. The
hhh argument references the
hhook
point to call all registered hook functions
for. The ctx_data argument specifies a pointer to the
contextual hook point data to pass into the hook functions. The
hosd argument should be the pointer to the appropriate
object's struct osd if the subsystem provides the
ability for Khelp modules to associate per-object data. Subsystems which do
not should pass NULL.
The
HHOOKS_RUN_IF
()
macro is the preferred way to implement hook points. It only calls the
hhook_run_hooks
() function if at least one hook
function is registered for the hook point. By checking for registered hook
functions, the macro minimises the cost associated with adding hook points
to frequently used code paths by reducing to a simple if test in the common
case where no hook functions are registered. The arguments are as described
for the hhook_run_hooks
() function.
The
HHOOKS_RUN_IF_LOOKUP
()
macro performs the same function as the
HHOOKS_RUN_IF
() macro, but performs an additional
step to look up the struct hhook_head for the
specified hook_type and hook_id
identifiers. It should not be used except in code paths which are
infrequently executed because of the reference counting overhead associated
with the look up.
IMPLEMENTATION NOTES
Each struct hhook_head protects its internal
list of hook functions with a
rmlock(9). Therefore, anytime
hhook_run_hooks
() is called directly or indirectly
via the HHOOKS_RUN_IF
() or
HHOOKS_RUN_IF_LOOKUP
() macros, a non-sleepable read
lock will be acquired and held across the calls to all registered hook
functions.
RETURN VALUES
hhook_head_register
() returns 0 if no
errors occurred. It returns EEXIST if a hook point with the same
hook_type and hook_id is already
registered. It returns EINVAL if the HHOOK_HEADISINVNET flag is not set in
flags because the implementation does not yet support
hook points in non-virtualised subsystems (see the
BUGS section for details). It returns ENOMEM
if malloc(9) failed to allocate memory for the new
struct hhook_head.
hhook_head_deregister
() and
hhook_head_deregister_lookup
() return 0 if no errors
occurred. They return ENOENT if hhh is NULL. They
return EBUSY if the reference count of hhh is greater
than one.
EXAMPLES
A well commented example Khelp module can be found at: /usr/share/examples/kld/khelp/h_example.c
The tcp(4) implementation provides two
hhook
points which are called for packets
sent/received when a connection is in the established phase. Search for
HHOOK in the following files: sys/netinet/tcp_var.h,
sys/netinet/tcp_input.c,
sys/netinet/tcp_output.c and
sys/netinet/tcp_subr.c.
SEE ALSO
ACKNOWLEDGEMENTS
Development and testing of this software were made possible in part by grants from the FreeBSD Foundation and Cisco University Research Program Fund at Community Foundation Silicon Valley.
HISTORY
The hhook
framework first appeared in
FreeBSD 9.0.
The hhook
framework was first released in
2010 by Lawrence Stewart whilst studying at Swinburne University of
Technology's Centre for Advanced Internet Architectures, Melbourne,
Australia. More details are available at:
http://caia.swin.edu.au/urp/newtcp/
AUTHORS
The hhook
framework was written by
Lawrence Stewart
<lstewart@FreeBSD.org>.
This manual page was written by David Hayes <david.hayes@ieee.org> and Lawrence Stewart <lstewart@FreeBSD.org>.