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 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