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