HHOOK(9)
π HHOOK β the Helper Hook Framework π
okay bestie, so this one is from the Kernel Developer's Manual (section 9, kernel interfaces, iykyk) and it's literally all about hooking functions into the kernel at specific points. it's giving plug-and-play but for kernel code. let's get into it π«Ά
β¨ NAME β¨
hhook, hhook_head_register, hhook_head_deregister, hhook_head_deregister_lookup, hhook_run_hooks, HHOOKS_RUN_IF, HHOOKS_RUN_LOOKUP_IF β the 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 β¨
so hhook is a whole framework for managing and running arbitrary hook functions at defined hook points inside the kernel. the KPI was inspired by pfil(9), and honestly in a lot of ways you can think of it as a more generic superset of pfil. iconic behaviour, no cap. π
the khelp(9) and hhook frameworks are tightly integrated, like they're literally besties. Khelp is the one responsible for registering and deregistering Khelp module hook functions with hhook points. the KPI functions that khelp(9) uses to do that are not documented here, because they're not relevant to consumers who just wanna instantiate hook points. not me gatekeeping, it's just not your business π
πΈ Information for Khelp Module Implementors πΈ
Khelp modules interact with hhook indirectly, by defining appropriate hook functions for insertion into hook points. hook functions must conform to the hhook_func_t function pointer declaration laid out in the βSYNOPSISβ. periodt.
the hhook_type and hhook_id arguments identify which hook point called into the hook function. these are super useful when a single hook function is registered for multiple hook points and it wants to know which hook point called into it. <sys/hhook.h> lists the available hhook_type defines, and the subsystems which export hook points are responsible for defining the hhook_id value in appropriate header files.
the udata argument gets 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 β so like, don't assume, bestie.
the hdata argument is a pointer to the persistent per-object storage allocated for use by the module, if required. that 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. sharing is caring π«Ά
Khelp modules tell 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. not your job, don't touch it π
π Creating and Managing Hook Points π
kernel subsystems that wanna provide hhook points typically need to make four, and possibly five, key changes to their implementation:
- Define a list of
hhook_idmappings 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 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. and 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 doesn't 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. look it up, bestie π
the hhook_run_hooks() function should normally not be called directly β it should instead be called indirectly via the HHOOKS_RUN_IF() macro. however, there may be circumstances where it's preferable to call the function directly, and so it's 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 don't 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 β it reduces 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 does 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. lowkey expensive, so use it sparingly π
β¨ IMPLEMENTATION NOTES β¨
each struct hhook_head protects its internal list of hook functions with an 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. lock in fr fr π
β¨ 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. go read the source bestie, it's giving education π
β¨ 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. real ones π«Ά
β¨ 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>.
and that's the whole page bestie π this Debian build of the page is dated June 21, 2013 β so yeah it's vintage but it still ate. go forth and hook responsibly πβ¨π¦
π¦ where this page comes from
- debian bookworm: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- debian trixie: freebsd-manpages 12.2-2 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu jammy: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu noble: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu questing: freebsd-manpages 12.2-2
- ubuntu resolute: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu stonking: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- Copyright (c) 2010-2011 The FreeBSD Foundation
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms