1218545Slstewart/*- 2218545Slstewart * Copyright (c) 2010-2011 The FreeBSD Foundation 3218545Slstewart * All rights reserved. 4218545Slstewart * 5218545Slstewart * This software was developed at the Centre for Advanced Internet 6218545Slstewart * Architectures, Swinburne University of Technology, Melbourne, Australia by 7218545Slstewart * Lawrence Stewart under sponsorship from the FreeBSD Foundation. 8218545Slstewart * 9218545Slstewart * Redistribution and use in source and binary forms, with or without 10218545Slstewart * modification, are permitted provided that the following conditions 11218545Slstewart * are met: 12218545Slstewart * 1. Redistributions of source code must retain the above copyright 13218545Slstewart * notice, this list of conditions and the following disclaimer. 14218545Slstewart * 2. Redistributions in binary form must reproduce the above copyright 15218545Slstewart * notice, this list of conditions and the following disclaimer in the 16218545Slstewart * documentation and/or other materials provided with the distribution. 17218545Slstewart * 18218545Slstewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19218545Slstewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20218545Slstewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21218545Slstewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22218545Slstewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23218545Slstewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24218545Slstewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25218545Slstewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26218545Slstewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27218545Slstewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28218545Slstewart * SUCH DAMAGE. 29218545Slstewart */ 30218545Slstewart 31218545Slstewart/* 32218545Slstewart * This example Khelp module uses the helper hook points available in the TCP 33218545Slstewart * stack to calculate a per-connection count of inbound and outbound packets 34218545Slstewart * when the connection is in the established state. The code is verbosely 35218545Slstewart * documented in an attempt to explain how everything fits together. 36218545Slstewart */ 37218545Slstewart 38218545Slstewart#include <sys/cdefs.h> 39218545Slstewart__FBSDID("$FreeBSD$"); 40218545Slstewart 41218545Slstewart#include <sys/param.h> 42218545Slstewart#include <sys/kernel.h> 43218545Slstewart#include <sys/hhook.h> 44218545Slstewart#include <sys/khelp.h> 45218545Slstewart#include <sys/module.h> 46218545Slstewart#include <sys/module_khelp.h> 47218545Slstewart#include <sys/socket.h> 48218545Slstewart#include <sys/socketvar.h> 49218545Slstewart 50218545Slstewart#include <netinet/tcp_var.h> 51218545Slstewart 52218545Slstewart#include <vm/uma.h> 53218545Slstewart 54218545Slstewart/* 55218545Slstewart * Function prototype for our helper hook (man 9 hhook) compatible hook 56218545Slstewart * function. 57218545Slstewart */ 58218545Slstewartstatic int example_hook(int hhook_type, int hhook_id, void *udata, 59218545Slstewart void *ctx_data, void *hdata, struct osd *hosd); 60218545Slstewart 61218545Slstewart/* 62218545Slstewart * Our per-connection persistent data storage struct. 63218545Slstewart */ 64218545Slstewartstruct example { 65218545Slstewart uint32_t est_in_count; 66218545Slstewart uint32_t est_out_count; 67218545Slstewart}; 68218545Slstewart 69218545Slstewart/* 70218545Slstewart * Fill in the required bits of our module's struct helper (defined in 71218545Slstewart * <sys/module_khelp.h>). 72218545Slstewart * 73218545Slstewart * - Our helper will be storing persistent state for each TCP connection, so we 74218545Slstewart * request the use the Object Specific Data (OSD) feature from the framework by 75218545Slstewart * setting the HELPER_NEEDS_OSD flag. 76218545Slstewart * 77218545Slstewart * - Our helper is related to the TCP subsystem, so tell the Khelp framework 78218545Slstewart * this by setting an appropriate class for the module. When a new TCP 79218545Slstewart * connection is created, the Khelp framework takes care of associating helper 80218545Slstewart * modules of the appropriate class with the new connection. 81218545Slstewart */ 82218545Slstewartstruct helper example_helper = { 83218545Slstewart .h_flags = HELPER_NEEDS_OSD, 84218545Slstewart .h_classes = HELPER_CLASS_TCP 85218545Slstewart}; 86218545Slstewart 87218545Slstewart/* 88218545Slstewart * Set which helper hook points our module wants to hook by creating an array of 89218545Slstewart * hookinfo structs (defined in <sys/hhook.h>). We hook the TCP established 90218545Slstewart * inbound/outbound hook points (TCP hhook points are defined in 91218545Slstewart * <netinet/tcp_var.h>) with our example_hook() function. We don't require a user 92218545Slstewart * data pointer to be passed to our hook function when called, so we set it to 93218545Slstewart * NULL. 94218545Slstewart */ 95218545Slstewartstruct hookinfo example_hooks[] = { 96218545Slstewart { 97218545Slstewart .hook_type = HHOOK_TYPE_TCP, 98218545Slstewart .hook_id = HHOOK_TCP_EST_IN, 99218545Slstewart .hook_udata = NULL, 100218545Slstewart .hook_func = &example_hook 101218545Slstewart }, 102218545Slstewart { 103218545Slstewart .hook_type = HHOOK_TYPE_TCP, 104218545Slstewart .hook_id = HHOOK_TCP_EST_OUT, 105218545Slstewart .hook_udata = NULL, 106218545Slstewart .hook_func = &example_hook 107218545Slstewart } 108218545Slstewart}; 109218545Slstewart 110218545Slstewart/* 111218545Slstewart * Very simple helper hook function. Here's a quick run through the arguments: 112218545Slstewart * 113218545Slstewart * - hhook_type and hhook_id are useful if you use a single function with many 114218545Slstewart * hook points and want to know which hook point called the function. 115218545Slstewart * 116218545Slstewart * - udata will be NULL, because we didn't elect to pass a pointer in either of 117218545Slstewart * the hookinfo structs we instantiated above in the example_hooks array. 118218545Slstewart * 119218545Slstewart * - ctx_data contains context specific data from the hook point call site. The 120218545Slstewart * data type passed is subsystem dependent. In the case of TCP, the hook points 121218545Slstewart * pass a pointer to a "struct tcp_hhook_data" (defined in <netinet/tcp_var.h>). 122218545Slstewart * 123218545Slstewart * - hdata is a pointer to the persistent per-object storage for our module. The 124218545Slstewart * pointer is allocated automagically by the Khelp framework when the connection 125218545Slstewart * is created, and comes from a dedicated UMA zone. It will never be NULL. 126218545Slstewart * 127218545Slstewart * - hosd can be used with the Khelp framework's khelp_get_osd() function to 128218545Slstewart * access data belonging to a different Khelp module. 129218545Slstewart */ 130218545Slstewartstatic int 131218545Slstewartexample_hook(int hhook_type, int hhook_id, void *udata, void *ctx_data, 132218545Slstewart void *hdata, struct osd *hosd) 133218545Slstewart{ 134218545Slstewart struct example *data; 135218545Slstewart 136218545Slstewart data = hdata; 137218545Slstewart 138218545Slstewart if (hhook_id == HHOOK_TCP_EST_IN) 139218545Slstewart data->est_in_count++; 140218545Slstewart else if (hhook_id == HHOOK_TCP_EST_OUT) 141218545Slstewart data->est_out_count++; 142218545Slstewart 143218545Slstewart return (0); 144218545Slstewart} 145218545Slstewart 146218545Slstewart/* 147218545Slstewart * We use a convenient macro which handles registering our module with the Khelp 148218545Slstewart * framework. Note that Khelp modules which set the HELPER_NEEDS_OSD flag (i.e. 149218545Slstewart * require persistent per-object storage) must use the KHELP_DECLARE_MOD_UMA() 150218545Slstewart * macro. If you don't require per-object storage, use the KHELP_DECLARE_MOD() 151218545Slstewart * macro instead. 152218545Slstewart */ 153218545SlstewartKHELP_DECLARE_MOD_UMA(example, &example_helper, example_hooks, 1, 154218545Slstewart sizeof(struct example), NULL, NULL); 155