xref: /freebsd/share/examples/kld/khelp/h_example.c (revision 87b759f0fa1f7554d50ce640c40138512bbded44)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2010-2011 The FreeBSD Foundation
5  *
6  * This software was developed at the Centre for Advanced Internet
7  * Architectures, Swinburne University of Technology, Melbourne, Australia by
8  * Lawrence Stewart under sponsorship from the FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * This example Khelp module uses the helper hook points available in the TCP
34  * stack to calculate a per-connection count of inbound and outbound packets
35  * when the connection is in the established state. The code is verbosely
36  * documented in an attempt to explain how everything fits together.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/kernel.h>
41 #include <sys/hhook.h>
42 #include <sys/khelp.h>
43 #include <sys/module.h>
44 #include <sys/module_khelp.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 
48 #include <netinet/tcp_var.h>
49 
50 #include <vm/uma.h>
51 
52 /*
53  * Function prototype for our helper hook (man 9 hhook) compatible hook
54  * function.
55  */
56 static int example_hook(int hhook_type, int hhook_id, void *udata,
57     void *ctx_data, void *hdata, struct osd *hosd);
58 
59 /*
60  * Our per-connection persistent data storage struct.
61  */
62 struct example {
63 	uint32_t est_in_count;
64 	uint32_t est_out_count;
65 };
66 
67 /*
68  * Fill in the required bits of our module's struct helper (defined in
69  * <sys/module_khelp.h>).
70  *
71  * - Our helper will be storing persistent state for each TCP connection, so we
72  * request the use the Object Specific Data (OSD) feature from the framework by
73  * setting the HELPER_NEEDS_OSD flag.
74  *
75  * - Our helper is related to the TCP subsystem, so tell the Khelp framework
76  * this by setting an appropriate class for the module. When a new TCP
77  * connection is created, the Khelp framework takes care of associating helper
78  * modules of the appropriate class with the new connection.
79  */
80 struct helper example_helper = {
81 	.h_flags = HELPER_NEEDS_OSD,
82 	.h_classes = HELPER_CLASS_TCP
83 };
84 
85 /*
86  * Set which helper hook points our module wants to hook by creating an array of
87  * hookinfo structs (defined in <sys/hhook.h>). We hook the TCP established
88  * inbound/outbound hook points (TCP hhook points are defined in
89  * <netinet/tcp_var.h>) with our example_hook() function. We don't require a user
90  * data pointer to be passed to our hook function when called, so we set it to
91  * NULL.
92  */
93 struct hookinfo example_hooks[] = {
94 	{
95 		.hook_type = HHOOK_TYPE_TCP,
96 		.hook_id = HHOOK_TCP_EST_IN,
97 		.hook_udata = NULL,
98 		.hook_func = &example_hook
99 	},
100 	{
101 		.hook_type = HHOOK_TYPE_TCP,
102 		.hook_id = HHOOK_TCP_EST_OUT,
103 		.hook_udata = NULL,
104 		.hook_func = &example_hook
105 	}
106 };
107 
108 /*
109  * Very simple helper hook function. Here's a quick run through the arguments:
110  *
111  * - hhook_type and hhook_id are useful if you use a single function with many
112  * hook points and want to know which hook point called the function.
113  *
114  * - udata will be NULL, because we didn't elect to pass a pointer in either of
115  * the hookinfo structs we instantiated above in the example_hooks array.
116  *
117  * - ctx_data contains context specific data from the hook point call site. The
118  * data type passed is subsystem dependent. In the case of TCP, the hook points
119  * pass a pointer to a "struct tcp_hhook_data" (defined in <netinet/tcp_var.h>).
120  *
121  * - hdata is a pointer to the persistent per-object storage for our module. The
122  * pointer is allocated automagically by the Khelp framework when the connection
123  * is created, and comes from a dedicated UMA zone. It will never be NULL.
124  *
125  * - hosd can be used with the Khelp framework's khelp_get_osd() function to
126  * access data belonging to a different Khelp module.
127  */
128 static int
129 example_hook(int hhook_type, int hhook_id, void *udata, void *ctx_data,
130     void *hdata, struct osd *hosd)
131 {
132 	struct example *data;
133 
134 	data = hdata;
135 
136 	if (hhook_id == HHOOK_TCP_EST_IN)
137 		data->est_in_count++;
138 	else if (hhook_id == HHOOK_TCP_EST_OUT)
139 		data->est_out_count++;
140 
141 	return (0);
142 }
143 
144 /*
145  * We use a convenient macro which handles registering our module with the Khelp
146  * framework. Note that Khelp modules which set the HELPER_NEEDS_OSD flag (i.e.
147  * require persistent per-object storage) must use the KHELP_DECLARE_MOD_UMA()
148  * macro. If you don't require per-object storage, use the KHELP_DECLARE_MOD()
149  * macro instead.
150  */
151 KHELP_DECLARE_MOD_UMA(example, &example_helper, example_hooks, 1,
152     sizeof(struct example), NULL, NULL);
153