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