1216615Slstewart/*-
2251770Slstewart * Copyright (c) 2010,2013 Lawrence Stewart <lstewart@freebsd.org>
3216615Slstewart * Copyright (c) 2010 The FreeBSD Foundation
4216615Slstewart * All rights reserved.
5216615Slstewart *
6216615Slstewart * This software was developed by Lawrence Stewart while studying at the Centre
7220560Slstewart * for Advanced Internet Architectures, Swinburne University of Technology,
8220560Slstewart * made possible in part by grants from the FreeBSD Foundation and Cisco
9220560Slstewart * University Research Program Fund at Community Foundation Silicon Valley.
10216615Slstewart *
11216615Slstewart * Portions of this software were developed at the Centre for Advanced
12216615Slstewart * Internet Architectures, Swinburne University of Technology, Melbourne,
13216615Slstewart * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation.
14216615Slstewart *
15216615Slstewart * Redistribution and use in source and binary forms, with or without
16216615Slstewart * modification, are permitted provided that the following conditions
17216615Slstewart * are met:
18216615Slstewart * 1. Redistributions of source code must retain the above copyright
19216615Slstewart *    notice, this list of conditions and the following disclaimer.
20216615Slstewart * 2. Redistributions in binary form must reproduce the above copyright
21216615Slstewart *    notice, this list of conditions and the following disclaimer in the
22216615Slstewart *    documentation and/or other materials provided with the distribution.
23216615Slstewart *
24216615Slstewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25216615Slstewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26216615Slstewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27216615Slstewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28216615Slstewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29216615Slstewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30216615Slstewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31216615Slstewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32216615Slstewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33216615Slstewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34216615Slstewart * SUCH DAMAGE.
35216615Slstewart */
36216615Slstewart
37216615Slstewart#include <sys/cdefs.h>
38216615Slstewart__FBSDID("$FreeBSD: releng/10.3/sys/kern/kern_hhook.c 251787 2013-06-15 10:08:34Z lstewart $");
39216615Slstewart
40216615Slstewart#include <sys/param.h>
41216615Slstewart#include <sys/kernel.h>
42216615Slstewart#include <sys/hhook.h>
43216615Slstewart#include <sys/khelp.h>
44216615Slstewart#include <sys/malloc.h>
45216615Slstewart#include <sys/module.h>
46216615Slstewart#include <sys/module_khelp.h>
47216615Slstewart#include <sys/osd.h>
48216615Slstewart#include <sys/queue.h>
49216615Slstewart#include <sys/refcount.h>
50216615Slstewart#include <sys/systm.h>
51216615Slstewart
52216615Slstewart#include <net/vnet.h>
53216615Slstewart
54216615Slstewartstruct hhook {
55216615Slstewart	hhook_func_t		hhk_func;
56216615Slstewart	struct helper		*hhk_helper;
57216615Slstewart	void			*hhk_udata;
58216615Slstewart	STAILQ_ENTRY(hhook)	hhk_next;
59216615Slstewart};
60216615Slstewart
61220592Spluknetstatic MALLOC_DEFINE(M_HHOOK, "hhook", "Helper hooks are linked off hhook_head lists");
62216615Slstewart
63216615SlstewartLIST_HEAD(hhookheadhead, hhook_head);
64251732Slstewartstruct hhookheadhead hhook_head_list;
65251732SlstewartVNET_DEFINE(struct hhookheadhead, hhook_vhead_list);
66251732Slstewart#define	V_hhook_vhead_list VNET(hhook_vhead_list)
67216615Slstewart
68216615Slstewartstatic struct mtx hhook_head_list_lock;
69216615SlstewartMTX_SYSINIT(hhookheadlistlock, &hhook_head_list_lock, "hhook_head list lock",
70216615Slstewart    MTX_DEF);
71216615Slstewart
72251770Slstewart/* Protected by hhook_head_list_lock. */
73251770Slstewartstatic uint32_t n_hhookheads;
74251770Slstewart
75216615Slstewart/* Private function prototypes. */
76216615Slstewartstatic void hhook_head_destroy(struct hhook_head *hhh);
77251774Slstewartvoid khelp_new_hhook_registered(struct hhook_head *hhh, uint32_t flags);
78216615Slstewart
79216615Slstewart#define	HHHLIST_LOCK() mtx_lock(&hhook_head_list_lock)
80216615Slstewart#define	HHHLIST_UNLOCK() mtx_unlock(&hhook_head_list_lock)
81216615Slstewart#define	HHHLIST_LOCK_ASSERT() mtx_assert(&hhook_head_list_lock, MA_OWNED)
82216615Slstewart
83216615Slstewart#define	HHH_LOCK_INIT(hhh) rm_init(&(hhh)->hhh_lock, "hhook_head rm lock")
84216615Slstewart#define	HHH_LOCK_DESTROY(hhh) rm_destroy(&(hhh)->hhh_lock)
85216615Slstewart#define	HHH_WLOCK(hhh) rm_wlock(&(hhh)->hhh_lock)
86216615Slstewart#define	HHH_WUNLOCK(hhh) rm_wunlock(&(hhh)->hhh_lock)
87216615Slstewart#define	HHH_RLOCK(hhh, rmpt) rm_rlock(&(hhh)->hhh_lock, (rmpt))
88216615Slstewart#define	HHH_RUNLOCK(hhh, rmpt) rm_runlock(&(hhh)->hhh_lock, (rmpt))
89216615Slstewart
90216615Slstewart/*
91216615Slstewart * Run all helper hook functions for a given hook point.
92216615Slstewart */
93216615Slstewartvoid
94216615Slstewarthhook_run_hooks(struct hhook_head *hhh, void *ctx_data, struct osd *hosd)
95216615Slstewart{
96216615Slstewart	struct hhook *hhk;
97216615Slstewart	void *hdata;
98216615Slstewart	struct rm_priotracker rmpt;
99216615Slstewart
100216615Slstewart	KASSERT(hhh->hhh_refcount > 0, ("hhook_head %p refcount is 0", hhh));
101216615Slstewart
102216615Slstewart	HHH_RLOCK(hhh, &rmpt);
103216615Slstewart	STAILQ_FOREACH(hhk, &hhh->hhh_hooks, hhk_next) {
104216615Slstewart		if (hhk->hhk_helper->h_flags & HELPER_NEEDS_OSD) {
105216615Slstewart			hdata = osd_get(OSD_KHELP, hosd, hhk->hhk_helper->h_id);
106216615Slstewart			if (hdata == NULL)
107216615Slstewart				continue;
108216615Slstewart		} else
109216615Slstewart			hdata = NULL;
110216615Slstewart
111216615Slstewart		/*
112216615Slstewart		 * XXXLAS: We currently ignore the int returned by the hook,
113216615Slstewart		 * but will likely want to handle it in future to allow hhook to
114216615Slstewart		 * be used like pfil and effect changes at the hhook calling
115216615Slstewart		 * site e.g. we could define a new hook type of HHOOK_TYPE_PFIL
116216615Slstewart		 * and standardise what particular return values mean and set
117216615Slstewart		 * the context data to pass exactly the same information as pfil
118216615Slstewart		 * hooks currently receive, thus replicating pfil with hhook.
119216615Slstewart		 */
120216615Slstewart		hhk->hhk_func(hhh->hhh_type, hhh->hhh_id, hhk->hhk_udata,
121216615Slstewart		    ctx_data, hdata, hosd);
122216615Slstewart	}
123216615Slstewart	HHH_RUNLOCK(hhh, &rmpt);
124216615Slstewart}
125216615Slstewart
126216615Slstewart/*
127216615Slstewart * Register a new helper hook function with a helper hook point.
128216615Slstewart */
129216615Slstewartint
130216615Slstewarthhook_add_hook(struct hhook_head *hhh, struct hookinfo *hki, uint32_t flags)
131216615Slstewart{
132216615Slstewart	struct hhook *hhk, *tmp;
133216615Slstewart	int error;
134216615Slstewart
135216615Slstewart	error = 0;
136216615Slstewart
137216615Slstewart	if (hhh == NULL)
138216615Slstewart		return (ENOENT);
139216615Slstewart
140216615Slstewart	hhk = malloc(sizeof(struct hhook), M_HHOOK,
141216615Slstewart	    M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT));
142216615Slstewart
143216615Slstewart	if (hhk == NULL)
144216615Slstewart		return (ENOMEM);
145216615Slstewart
146216615Slstewart	hhk->hhk_helper = hki->hook_helper;
147216615Slstewart	hhk->hhk_func = hki->hook_func;
148216615Slstewart	hhk->hhk_udata = hki->hook_udata;
149216615Slstewart
150216615Slstewart	HHH_WLOCK(hhh);
151216615Slstewart	STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) {
152216615Slstewart		if (tmp->hhk_func == hki->hook_func &&
153216615Slstewart		    tmp->hhk_udata == hki->hook_udata) {
154216615Slstewart			/* The helper hook function is already registered. */
155216615Slstewart			error = EEXIST;
156216615Slstewart			break;
157216615Slstewart		}
158216615Slstewart	}
159216615Slstewart
160216615Slstewart	if (!error) {
161216615Slstewart		STAILQ_INSERT_TAIL(&hhh->hhh_hooks, hhk, hhk_next);
162216615Slstewart		hhh->hhh_nhooks++;
163217248Slstewart	} else
164216615Slstewart		free(hhk, M_HHOOK);
165216615Slstewart
166216615Slstewart	HHH_WUNLOCK(hhh);
167216615Slstewart
168216615Slstewart	return (error);
169216615Slstewart}
170216615Slstewart
171216615Slstewart/*
172251770Slstewart * Register a helper hook function with a helper hook point (including all
173251770Slstewart * virtual instances of the hook point if it is virtualised).
174251770Slstewart *
175251770Slstewart * The logic is unfortunately far more complex than for
176251770Slstewart * hhook_remove_hook_lookup() because hhook_add_hook() can call malloc() with
177251770Slstewart * M_WAITOK and thus we cannot call hhook_add_hook() with the
178251770Slstewart * hhook_head_list_lock held.
179251770Slstewart *
180251770Slstewart * The logic assembles an array of hhook_head structs that correspond to the
181251770Slstewart * helper hook point being hooked and bumps the refcount on each (all done with
182251770Slstewart * the hhook_head_list_lock held). The hhook_head_list_lock is then dropped, and
183251770Slstewart * hhook_add_hook() is called and the refcount dropped for each hhook_head
184251770Slstewart * struct in the array.
185216615Slstewart */
186216615Slstewartint
187216615Slstewarthhook_add_hook_lookup(struct hookinfo *hki, uint32_t flags)
188216615Slstewart{
189251770Slstewart	struct hhook_head **heads_to_hook, *hhh;
190251770Slstewart	int error, i, n_heads_to_hook;
191216615Slstewart
192251770Slstewarttryagain:
193251770Slstewart	error = i = 0;
194251770Slstewart	/*
195251770Slstewart	 * Accessing n_hhookheads without hhook_head_list_lock held opens up a
196251770Slstewart	 * race with hhook_head_register() which we are unlikely to lose, but
197251770Slstewart	 * nonetheless have to cope with - hence the complex goto logic.
198251770Slstewart	 */
199251770Slstewart	n_heads_to_hook = n_hhookheads;
200251770Slstewart	heads_to_hook = malloc(n_heads_to_hook * sizeof(struct hhook_head *),
201251770Slstewart	    M_HHOOK, flags & HHOOK_WAITOK ? M_WAITOK : M_NOWAIT);
202251770Slstewart	if (heads_to_hook == NULL)
203251770Slstewart		return (ENOMEM);
204216615Slstewart
205251770Slstewart	HHHLIST_LOCK();
206251770Slstewart	LIST_FOREACH(hhh, &hhook_head_list, hhh_next) {
207251770Slstewart		if (hhh->hhh_type == hki->hook_type &&
208251770Slstewart		    hhh->hhh_id == hki->hook_id) {
209251770Slstewart			if (i < n_heads_to_hook) {
210251770Slstewart				heads_to_hook[i] = hhh;
211251770Slstewart				refcount_acquire(&heads_to_hook[i]->hhh_refcount);
212251770Slstewart				i++;
213251770Slstewart			} else {
214251770Slstewart				/*
215251770Slstewart				 * We raced with hhook_head_register() which
216251770Slstewart				 * inserted a hhook_head that we need to hook
217251770Slstewart				 * but did not malloc space for. Abort this run
218251770Slstewart				 * and try again.
219251770Slstewart				 */
220251770Slstewart				for (i--; i >= 0; i--)
221251770Slstewart					refcount_release(&heads_to_hook[i]->hhh_refcount);
222251770Slstewart				free(heads_to_hook, M_HHOOK);
223251770Slstewart				HHHLIST_UNLOCK();
224251770Slstewart				goto tryagain;
225251770Slstewart			}
226251770Slstewart		}
227251770Slstewart	}
228251770Slstewart	HHHLIST_UNLOCK();
229216615Slstewart
230251770Slstewart	for (i--; i >= 0; i--) {
231251770Slstewart		if (!error)
232251770Slstewart			error = hhook_add_hook(heads_to_hook[i], hki, flags);
233251770Slstewart		refcount_release(&heads_to_hook[i]->hhh_refcount);
234251770Slstewart	}
235216615Slstewart
236251770Slstewart	free(heads_to_hook, M_HHOOK);
237251770Slstewart
238216615Slstewart	return (error);
239216615Slstewart}
240216615Slstewart
241216615Slstewart/*
242216615Slstewart * Remove a helper hook function from a helper hook point.
243216615Slstewart */
244216615Slstewartint
245216615Slstewarthhook_remove_hook(struct hhook_head *hhh, struct hookinfo *hki)
246216615Slstewart{
247216615Slstewart	struct hhook *tmp;
248216615Slstewart
249216615Slstewart	if (hhh == NULL)
250216615Slstewart		return (ENOENT);
251216615Slstewart
252216615Slstewart	HHH_WLOCK(hhh);
253216615Slstewart	STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) {
254216615Slstewart		if (tmp->hhk_func == hki->hook_func &&
255216615Slstewart		    tmp->hhk_udata == hki->hook_udata) {
256216615Slstewart			STAILQ_REMOVE(&hhh->hhh_hooks, tmp, hhook, hhk_next);
257216615Slstewart			free(tmp, M_HHOOK);
258216615Slstewart			hhh->hhh_nhooks--;
259216615Slstewart			break;
260216615Slstewart		}
261216615Slstewart	}
262216615Slstewart	HHH_WUNLOCK(hhh);
263216615Slstewart
264216615Slstewart	return (0);
265216615Slstewart}
266216615Slstewart
267216615Slstewart/*
268251770Slstewart * Remove a helper hook function from a helper hook point (including all
269251770Slstewart * virtual instances of the hook point if it is virtualised).
270216615Slstewart */
271216615Slstewartint
272216615Slstewarthhook_remove_hook_lookup(struct hookinfo *hki)
273216615Slstewart{
274216615Slstewart	struct hhook_head *hhh;
275216615Slstewart
276251770Slstewart	HHHLIST_LOCK();
277251770Slstewart	LIST_FOREACH(hhh, &hhook_head_list, hhh_next) {
278251770Slstewart		if (hhh->hhh_type == hki->hook_type &&
279251770Slstewart		    hhh->hhh_id == hki->hook_id)
280251770Slstewart			hhook_remove_hook(hhh, hki);
281251770Slstewart	}
282251770Slstewart	HHHLIST_UNLOCK();
283216615Slstewart
284216615Slstewart	return (0);
285216615Slstewart}
286216615Slstewart
287216615Slstewart/*
288216615Slstewart * Register a new helper hook point.
289216615Slstewart */
290216615Slstewartint
291216615Slstewarthhook_head_register(int32_t hhook_type, int32_t hhook_id, struct hhook_head **hhh,
292216615Slstewart    uint32_t flags)
293216615Slstewart{
294216615Slstewart	struct hhook_head *tmphhh;
295216615Slstewart
296216615Slstewart	tmphhh = hhook_head_get(hhook_type, hhook_id);
297216615Slstewart
298216615Slstewart	if (tmphhh != NULL) {
299216615Slstewart		/* Hook point previously registered. */
300216615Slstewart		hhook_head_release(tmphhh);
301216615Slstewart		return (EEXIST);
302216615Slstewart	}
303216615Slstewart
304216615Slstewart	tmphhh = malloc(sizeof(struct hhook_head), M_HHOOK,
305216615Slstewart	    M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT));
306216615Slstewart
307216615Slstewart	if (tmphhh == NULL)
308216615Slstewart		return (ENOMEM);
309216615Slstewart
310216615Slstewart	tmphhh->hhh_type = hhook_type;
311216615Slstewart	tmphhh->hhh_id = hhook_id;
312216615Slstewart	tmphhh->hhh_nhooks = 0;
313216615Slstewart	STAILQ_INIT(&tmphhh->hhh_hooks);
314216615Slstewart	HHH_LOCK_INIT(tmphhh);
315251774Slstewart	refcount_init(&tmphhh->hhh_refcount, 1);
316216615Slstewart
317251732Slstewart	HHHLIST_LOCK();
318216615Slstewart	if (flags & HHOOK_HEADISINVNET) {
319216615Slstewart		tmphhh->hhh_flags |= HHH_ISINVNET;
320251752Slstewart#ifdef VIMAGE
321251732Slstewart		KASSERT(curvnet != NULL, ("curvnet is NULL"));
322251732Slstewart		tmphhh->hhh_vid = (uintptr_t)curvnet;
323251732Slstewart		LIST_INSERT_HEAD(&V_hhook_vhead_list, tmphhh, hhh_vnext);
324251752Slstewart#endif
325216615Slstewart	}
326251732Slstewart	LIST_INSERT_HEAD(&hhook_head_list, tmphhh, hhh_next);
327251770Slstewart	n_hhookheads++;
328251732Slstewart	HHHLIST_UNLOCK();
329216615Slstewart
330251774Slstewart	khelp_new_hhook_registered(tmphhh, flags);
331251774Slstewart
332251774Slstewart	if (hhh != NULL)
333251774Slstewart		*hhh = tmphhh;
334251774Slstewart	else
335251774Slstewart		refcount_release(&tmphhh->hhh_refcount);
336251774Slstewart
337216615Slstewart	return (0);
338216615Slstewart}
339216615Slstewart
340216615Slstewartstatic void
341216615Slstewarthhook_head_destroy(struct hhook_head *hhh)
342216615Slstewart{
343216615Slstewart	struct hhook *tmp, *tmp2;
344216615Slstewart
345216615Slstewart	HHHLIST_LOCK_ASSERT();
346251770Slstewart	KASSERT(n_hhookheads > 0, ("n_hhookheads should be > 0"));
347216615Slstewart
348216615Slstewart	LIST_REMOVE(hhh, hhh_next);
349251752Slstewart#ifdef VIMAGE
350251732Slstewart	if (hhook_head_is_virtualised(hhh) == HHOOK_HEADISINVNET)
351251732Slstewart		LIST_REMOVE(hhh, hhh_vnext);
352251752Slstewart#endif
353216615Slstewart	HHH_WLOCK(hhh);
354216615Slstewart	STAILQ_FOREACH_SAFE(tmp, &hhh->hhh_hooks, hhk_next, tmp2)
355216615Slstewart		free(tmp, M_HHOOK);
356216615Slstewart	HHH_WUNLOCK(hhh);
357216615Slstewart	HHH_LOCK_DESTROY(hhh);
358216615Slstewart	free(hhh, M_HHOOK);
359251770Slstewart	n_hhookheads--;
360216615Slstewart}
361216615Slstewart
362216615Slstewart/*
363216615Slstewart * Remove a helper hook point.
364216615Slstewart */
365216615Slstewartint
366216615Slstewarthhook_head_deregister(struct hhook_head *hhh)
367216615Slstewart{
368216615Slstewart	int error;
369216615Slstewart
370216615Slstewart	error = 0;
371216615Slstewart
372216615Slstewart	HHHLIST_LOCK();
373216615Slstewart	if (hhh == NULL)
374216615Slstewart		error = ENOENT;
375216615Slstewart	else if (hhh->hhh_refcount > 1)
376216615Slstewart		error = EBUSY;
377216615Slstewart	else
378216615Slstewart		hhook_head_destroy(hhh);
379216615Slstewart	HHHLIST_UNLOCK();
380216615Slstewart
381216615Slstewart	return (error);
382216615Slstewart}
383216615Slstewart
384216615Slstewart/*
385216615Slstewart * Remove a helper hook point via a hhook_head lookup.
386216615Slstewart */
387216615Slstewartint
388216615Slstewarthhook_head_deregister_lookup(int32_t hhook_type, int32_t hhook_id)
389216615Slstewart{
390216615Slstewart	struct hhook_head *hhh;
391216615Slstewart	int error;
392216615Slstewart
393216615Slstewart	hhh = hhook_head_get(hhook_type, hhook_id);
394216615Slstewart	error = hhook_head_deregister(hhh);
395216615Slstewart
396216615Slstewart	if (error == EBUSY)
397216615Slstewart		hhook_head_release(hhh);
398216615Slstewart
399216615Slstewart	return (error);
400216615Slstewart}
401216615Slstewart
402216615Slstewart/*
403216615Slstewart * Lookup and return the hhook_head struct associated with the specified type
404216615Slstewart * and id, or NULL if not found. If found, the hhook_head's refcount is bumped.
405216615Slstewart */
406216615Slstewartstruct hhook_head *
407216615Slstewarthhook_head_get(int32_t hhook_type, int32_t hhook_id)
408216615Slstewart{
409216615Slstewart	struct hhook_head *hhh;
410216615Slstewart
411216615Slstewart	HHHLIST_LOCK();
412251732Slstewart	LIST_FOREACH(hhh, &hhook_head_list, hhh_next) {
413216615Slstewart		if (hhh->hhh_type == hhook_type && hhh->hhh_id == hhook_id) {
414251752Slstewart#ifdef VIMAGE
415251732Slstewart			if (hhook_head_is_virtualised(hhh) ==
416251732Slstewart			    HHOOK_HEADISINVNET) {
417251732Slstewart				KASSERT(curvnet != NULL, ("curvnet is NULL"));
418251732Slstewart				if (hhh->hhh_vid != (uintptr_t)curvnet)
419251732Slstewart					continue;
420251732Slstewart			}
421251752Slstewart#endif
422216615Slstewart			refcount_acquire(&hhh->hhh_refcount);
423217248Slstewart			break;
424216615Slstewart		}
425216615Slstewart	}
426216615Slstewart	HHHLIST_UNLOCK();
427216615Slstewart
428217248Slstewart	return (hhh);
429216615Slstewart}
430216615Slstewart
431216615Slstewartvoid
432216615Slstewarthhook_head_release(struct hhook_head *hhh)
433216615Slstewart{
434216615Slstewart
435216615Slstewart	refcount_release(&hhh->hhh_refcount);
436216615Slstewart}
437216615Slstewart
438216615Slstewart/*
439216615Slstewart * Check the hhook_head private flags and return the appropriate public
440216615Slstewart * representation of the flag to the caller. The function is implemented in a
441216615Slstewart * way that allows us to cope with other subsystems becoming virtualised in the
442216615Slstewart * future.
443216615Slstewart */
444216615Slstewartuint32_t
445216615Slstewarthhook_head_is_virtualised(struct hhook_head *hhh)
446216615Slstewart{
447216615Slstewart	uint32_t ret;
448216615Slstewart
449217250Slstewart	ret = 0;
450216615Slstewart
451217250Slstewart	if (hhh != NULL) {
452217250Slstewart		if (hhh->hhh_flags & HHH_ISINVNET)
453217250Slstewart			ret = HHOOK_HEADISINVNET;
454217250Slstewart	}
455216615Slstewart
456216615Slstewart	return (ret);
457216615Slstewart}
458216615Slstewart
459216615Slstewartuint32_t
460216615Slstewarthhook_head_is_virtualised_lookup(int32_t hook_type, int32_t hook_id)
461216615Slstewart{
462216615Slstewart	struct hhook_head *hhh;
463216615Slstewart	uint32_t ret;
464216615Slstewart
465216615Slstewart	hhh = hhook_head_get(hook_type, hook_id);
466216615Slstewart
467216615Slstewart	if (hhh == NULL)
468216615Slstewart		return (0);
469216615Slstewart
470216615Slstewart	ret = hhook_head_is_virtualised(hhh);
471216615Slstewart	hhook_head_release(hhh);
472216615Slstewart
473216615Slstewart	return (ret);
474216615Slstewart}
475216615Slstewart
476216615Slstewart/*
477216615Slstewart * Vnet created and being initialised.
478216615Slstewart */
479216615Slstewartstatic void
480216615Slstewarthhook_vnet_init(const void *unused __unused)
481216615Slstewart{
482216615Slstewart
483251732Slstewart	LIST_INIT(&V_hhook_vhead_list);
484216615Slstewart}
485216615Slstewart
486216615Slstewart/*
487216615Slstewart * Vnet being torn down and destroyed.
488216615Slstewart */
489216615Slstewartstatic void
490216615Slstewarthhook_vnet_uninit(const void *unused __unused)
491216615Slstewart{
492216615Slstewart	struct hhook_head *hhh, *tmphhh;
493216615Slstewart
494216615Slstewart	/*
495216615Slstewart	 * If subsystems which export helper hook points use the hhook KPI
496216615Slstewart	 * correctly, the loop below should have no work to do because the
497216615Slstewart	 * subsystem should have already called hhook_head_deregister().
498216615Slstewart	 */
499216615Slstewart	HHHLIST_LOCK();
500251732Slstewart	LIST_FOREACH_SAFE(hhh, &V_hhook_vhead_list, hhh_vnext, tmphhh) {
501216615Slstewart		printf("%s: hhook_head type=%d, id=%d cleanup required\n",
502216615Slstewart		    __func__, hhh->hhh_type, hhh->hhh_id);
503216615Slstewart		hhook_head_destroy(hhh);
504216615Slstewart	}
505216615Slstewart	HHHLIST_UNLOCK();
506216615Slstewart}
507216615Slstewart
508216615Slstewart
509216615Slstewart/*
510251732Slstewart * When a vnet is created and being initialised, init the V_hhook_vhead_list.
511216615Slstewart */
512251787SlstewartVNET_SYSINIT(hhook_vnet_init, SI_SUB_MBUF, SI_ORDER_FIRST,
513216615Slstewart    hhook_vnet_init, NULL);
514216615Slstewart
515216615Slstewart/*
516216615Slstewart * The hhook KPI provides a mechanism for subsystems which export helper hook
517216615Slstewart * points to clean up on vnet tear down, but in case the KPI is misused,
518216615Slstewart * provide a function to clean up and free memory for a vnet being destroyed.
519216615Slstewart */
520251787SlstewartVNET_SYSUNINIT(hhook_vnet_uninit, SI_SUB_MBUF, SI_ORDER_ANY,
521216615Slstewart    hhook_vnet_uninit, NULL);
522