xref: /freebsd/share/examples/kld/khelp/h_example.c (revision 5c2bc3db201a4fe8d7911cf816bea104d5dc2138)
112db289aSLawrence Stewart /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3f0cfa1b1SPedro F. Giffuni  *
412db289aSLawrence Stewart  * Copyright (c) 2010-2011 The FreeBSD Foundation
512db289aSLawrence Stewart  *
612db289aSLawrence Stewart  * This software was developed at the Centre for Advanced Internet
712db289aSLawrence Stewart  * Architectures, Swinburne University of Technology, Melbourne, Australia by
812db289aSLawrence Stewart  * Lawrence Stewart under sponsorship from the FreeBSD Foundation.
912db289aSLawrence Stewart  *
1012db289aSLawrence Stewart  * Redistribution and use in source and binary forms, with or without
1112db289aSLawrence Stewart  * modification, are permitted provided that the following conditions
1212db289aSLawrence Stewart  * are met:
1312db289aSLawrence Stewart  * 1. Redistributions of source code must retain the above copyright
1412db289aSLawrence Stewart  *    notice, this list of conditions and the following disclaimer.
1512db289aSLawrence Stewart  * 2. Redistributions in binary form must reproduce the above copyright
1612db289aSLawrence Stewart  *    notice, this list of conditions and the following disclaimer in the
1712db289aSLawrence Stewart  *    documentation and/or other materials provided with the distribution.
1812db289aSLawrence Stewart  *
1912db289aSLawrence Stewart  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2012db289aSLawrence Stewart  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2112db289aSLawrence Stewart  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2212db289aSLawrence Stewart  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2312db289aSLawrence Stewart  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2412db289aSLawrence Stewart  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2512db289aSLawrence Stewart  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2612db289aSLawrence Stewart  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2712db289aSLawrence Stewart  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2812db289aSLawrence Stewart  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2912db289aSLawrence Stewart  * SUCH DAMAGE.
3012db289aSLawrence Stewart  */
3112db289aSLawrence Stewart 
3212db289aSLawrence Stewart /*
3312db289aSLawrence Stewart  * This example Khelp module uses the helper hook points available in the TCP
3412db289aSLawrence Stewart  * stack to calculate a per-connection count of inbound and outbound packets
3512db289aSLawrence Stewart  * when the connection is in the established state. The code is verbosely
3612db289aSLawrence Stewart  * documented in an attempt to explain how everything fits together.
3712db289aSLawrence Stewart  */
3812db289aSLawrence Stewart 
3912db289aSLawrence Stewart #include <sys/param.h>
4012db289aSLawrence Stewart #include <sys/kernel.h>
4112db289aSLawrence Stewart #include <sys/hhook.h>
4212db289aSLawrence Stewart #include <sys/khelp.h>
4312db289aSLawrence Stewart #include <sys/module.h>
4412db289aSLawrence Stewart #include <sys/module_khelp.h>
4512db289aSLawrence Stewart #include <sys/socket.h>
4612db289aSLawrence Stewart #include <sys/socketvar.h>
4712db289aSLawrence Stewart 
4812db289aSLawrence Stewart #include <netinet/tcp_var.h>
4912db289aSLawrence Stewart 
5012db289aSLawrence Stewart #include <vm/uma.h>
5112db289aSLawrence Stewart 
5212db289aSLawrence Stewart /*
5312db289aSLawrence Stewart  * Function prototype for our helper hook (man 9 hhook) compatible hook
5412db289aSLawrence Stewart  * function.
5512db289aSLawrence Stewart  */
5612db289aSLawrence Stewart static int example_hook(int hhook_type, int hhook_id, void *udata,
5712db289aSLawrence Stewart     void *ctx_data, void *hdata, struct osd *hosd);
5812db289aSLawrence Stewart 
5912db289aSLawrence Stewart /*
6012db289aSLawrence Stewart  * Our per-connection persistent data storage struct.
6112db289aSLawrence Stewart  */
6212db289aSLawrence Stewart struct example {
6312db289aSLawrence Stewart 	uint32_t est_in_count;
6412db289aSLawrence Stewart 	uint32_t est_out_count;
6512db289aSLawrence Stewart };
6612db289aSLawrence Stewart 
6712db289aSLawrence Stewart /*
6812db289aSLawrence Stewart  * Fill in the required bits of our module's struct helper (defined in
6912db289aSLawrence Stewart  * <sys/module_khelp.h>).
7012db289aSLawrence Stewart  *
7112db289aSLawrence Stewart  * - Our helper will be storing persistent state for each TCP connection, so we
7212db289aSLawrence Stewart  * request the use the Object Specific Data (OSD) feature from the framework by
7312db289aSLawrence Stewart  * setting the HELPER_NEEDS_OSD flag.
7412db289aSLawrence Stewart  *
7512db289aSLawrence Stewart  * - Our helper is related to the TCP subsystem, so tell the Khelp framework
7612db289aSLawrence Stewart  * this by setting an appropriate class for the module. When a new TCP
7712db289aSLawrence Stewart  * connection is created, the Khelp framework takes care of associating helper
7812db289aSLawrence Stewart  * modules of the appropriate class with the new connection.
7912db289aSLawrence Stewart  */
8012db289aSLawrence Stewart struct helper example_helper = {
8112db289aSLawrence Stewart 	.h_flags = HELPER_NEEDS_OSD,
8212db289aSLawrence Stewart 	.h_classes = HELPER_CLASS_TCP
8312db289aSLawrence Stewart };
8412db289aSLawrence Stewart 
8512db289aSLawrence Stewart /*
8612db289aSLawrence Stewart  * Set which helper hook points our module wants to hook by creating an array of
8712db289aSLawrence Stewart  * hookinfo structs (defined in <sys/hhook.h>). We hook the TCP established
8812db289aSLawrence Stewart  * inbound/outbound hook points (TCP hhook points are defined in
8912db289aSLawrence Stewart  * <netinet/tcp_var.h>) with our example_hook() function. We don't require a user
9012db289aSLawrence Stewart  * data pointer to be passed to our hook function when called, so we set it to
9112db289aSLawrence Stewart  * NULL.
9212db289aSLawrence Stewart  */
9312db289aSLawrence Stewart struct hookinfo example_hooks[] = {
9412db289aSLawrence Stewart 	{
9512db289aSLawrence Stewart 		.hook_type = HHOOK_TYPE_TCP,
9612db289aSLawrence Stewart 		.hook_id = HHOOK_TCP_EST_IN,
9712db289aSLawrence Stewart 		.hook_udata = NULL,
9812db289aSLawrence Stewart 		.hook_func = &example_hook
9912db289aSLawrence Stewart 	},
10012db289aSLawrence Stewart 	{
10112db289aSLawrence Stewart 		.hook_type = HHOOK_TYPE_TCP,
10212db289aSLawrence Stewart 		.hook_id = HHOOK_TCP_EST_OUT,
10312db289aSLawrence Stewart 		.hook_udata = NULL,
10412db289aSLawrence Stewart 		.hook_func = &example_hook
10512db289aSLawrence Stewart 	}
10612db289aSLawrence Stewart };
10712db289aSLawrence Stewart 
10812db289aSLawrence Stewart /*
10912db289aSLawrence Stewart  * Very simple helper hook function. Here's a quick run through the arguments:
11012db289aSLawrence Stewart  *
11112db289aSLawrence Stewart  * - hhook_type and hhook_id are useful if you use a single function with many
11212db289aSLawrence Stewart  * hook points and want to know which hook point called the function.
11312db289aSLawrence Stewart  *
11412db289aSLawrence Stewart  * - udata will be NULL, because we didn't elect to pass a pointer in either of
11512db289aSLawrence Stewart  * the hookinfo structs we instantiated above in the example_hooks array.
11612db289aSLawrence Stewart  *
11712db289aSLawrence Stewart  * - ctx_data contains context specific data from the hook point call site. The
11812db289aSLawrence Stewart  * data type passed is subsystem dependent. In the case of TCP, the hook points
11912db289aSLawrence Stewart  * pass a pointer to a "struct tcp_hhook_data" (defined in <netinet/tcp_var.h>).
12012db289aSLawrence Stewart  *
12112db289aSLawrence Stewart  * - hdata is a pointer to the persistent per-object storage for our module. The
12212db289aSLawrence Stewart  * pointer is allocated automagically by the Khelp framework when the connection
12312db289aSLawrence Stewart  * is created, and comes from a dedicated UMA zone. It will never be NULL.
12412db289aSLawrence Stewart  *
12512db289aSLawrence Stewart  * - hosd can be used with the Khelp framework's khelp_get_osd() function to
12612db289aSLawrence Stewart  * access data belonging to a different Khelp module.
12712db289aSLawrence Stewart  */
12812db289aSLawrence Stewart static int
12912db289aSLawrence Stewart example_hook(int hhook_type, int hhook_id, void *udata, void *ctx_data,
13012db289aSLawrence Stewart     void *hdata, struct osd *hosd)
13112db289aSLawrence Stewart {
13212db289aSLawrence Stewart 	struct example *data;
13312db289aSLawrence Stewart 
13412db289aSLawrence Stewart 	data = hdata;
13512db289aSLawrence Stewart 
13612db289aSLawrence Stewart 	if (hhook_id == HHOOK_TCP_EST_IN)
13712db289aSLawrence Stewart 		data->est_in_count++;
13812db289aSLawrence Stewart 	else if (hhook_id == HHOOK_TCP_EST_OUT)
13912db289aSLawrence Stewart 		data->est_out_count++;
14012db289aSLawrence Stewart 
14112db289aSLawrence Stewart 	return (0);
14212db289aSLawrence Stewart }
14312db289aSLawrence Stewart 
14412db289aSLawrence Stewart /*
14512db289aSLawrence Stewart  * We use a convenient macro which handles registering our module with the Khelp
14612db289aSLawrence Stewart  * framework. Note that Khelp modules which set the HELPER_NEEDS_OSD flag (i.e.
14712db289aSLawrence Stewart  * require persistent per-object storage) must use the KHELP_DECLARE_MOD_UMA()
14812db289aSLawrence Stewart  * macro. If you don't require per-object storage, use the KHELP_DECLARE_MOD()
14912db289aSLawrence Stewart  * macro instead.
15012db289aSLawrence Stewart  */
15112db289aSLawrence Stewart KHELP_DECLARE_MOD_UMA(example, &example_helper, example_hooks, 1,
15212db289aSLawrence Stewart     sizeof(struct example), NULL, NULL);
153