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