kern_hhook.c revision 251770
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: head/sys/kern/kern_hhook.c 251770 2013-06-15 04:03:40Z 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);
77216615Slstewart
78216615Slstewart#define	HHHLIST_LOCK() mtx_lock(&hhook_head_list_lock)
79216615Slstewart#define	HHHLIST_UNLOCK() mtx_unlock(&hhook_head_list_lock)
80216615Slstewart#define	HHHLIST_LOCK_ASSERT() mtx_assert(&hhook_head_list_lock, MA_OWNED)
81216615Slstewart
82216615Slstewart#define	HHH_LOCK_INIT(hhh) rm_init(&(hhh)->hhh_lock, "hhook_head rm lock")
83216615Slstewart#define	HHH_LOCK_DESTROY(hhh) rm_destroy(&(hhh)->hhh_lock)
84216615Slstewart#define	HHH_WLOCK(hhh) rm_wlock(&(hhh)->hhh_lock)
85216615Slstewart#define	HHH_WUNLOCK(hhh) rm_wunlock(&(hhh)->hhh_lock)
86216615Slstewart#define	HHH_RLOCK(hhh, rmpt) rm_rlock(&(hhh)->hhh_lock, (rmpt))
87216615Slstewart#define	HHH_RUNLOCK(hhh, rmpt) rm_runlock(&(hhh)->hhh_lock, (rmpt))
88216615Slstewart
89216615Slstewart/*
90216615Slstewart * Run all helper hook functions for a given hook point.
91216615Slstewart */
92216615Slstewartvoid
93216615Slstewarthhook_run_hooks(struct hhook_head *hhh, void *ctx_data, struct osd *hosd)
94216615Slstewart{
95216615Slstewart	struct hhook *hhk;
96216615Slstewart	void *hdata;
97216615Slstewart	struct rm_priotracker rmpt;
98216615Slstewart
99216615Slstewart	KASSERT(hhh->hhh_refcount > 0, ("hhook_head %p refcount is 0", hhh));
100216615Slstewart
101216615Slstewart	HHH_RLOCK(hhh, &rmpt);
102216615Slstewart	STAILQ_FOREACH(hhk, &hhh->hhh_hooks, hhk_next) {
103216615Slstewart		if (hhk->hhk_helper->h_flags & HELPER_NEEDS_OSD) {
104216615Slstewart			hdata = osd_get(OSD_KHELP, hosd, hhk->hhk_helper->h_id);
105216615Slstewart			if (hdata == NULL)
106216615Slstewart				continue;
107216615Slstewart		} else
108216615Slstewart			hdata = NULL;
109216615Slstewart
110216615Slstewart		/*
111216615Slstewart		 * XXXLAS: We currently ignore the int returned by the hook,
112216615Slstewart		 * but will likely want to handle it in future to allow hhook to
113216615Slstewart		 * be used like pfil and effect changes at the hhook calling
114216615Slstewart		 * site e.g. we could define a new hook type of HHOOK_TYPE_PFIL
115216615Slstewart		 * and standardise what particular return values mean and set
116216615Slstewart		 * the context data to pass exactly the same information as pfil
117216615Slstewart		 * hooks currently receive, thus replicating pfil with hhook.
118216615Slstewart		 */
119216615Slstewart		hhk->hhk_func(hhh->hhh_type, hhh->hhh_id, hhk->hhk_udata,
120216615Slstewart		    ctx_data, hdata, hosd);
121216615Slstewart	}
122216615Slstewart	HHH_RUNLOCK(hhh, &rmpt);
123216615Slstewart}
124216615Slstewart
125216615Slstewart/*
126216615Slstewart * Register a new helper hook function with a helper hook point.
127216615Slstewart */
128216615Slstewartint
129216615Slstewarthhook_add_hook(struct hhook_head *hhh, struct hookinfo *hki, uint32_t flags)
130216615Slstewart{
131216615Slstewart	struct hhook *hhk, *tmp;
132216615Slstewart	int error;
133216615Slstewart
134216615Slstewart	error = 0;
135216615Slstewart
136216615Slstewart	if (hhh == NULL)
137216615Slstewart		return (ENOENT);
138216615Slstewart
139216615Slstewart	hhk = malloc(sizeof(struct hhook), M_HHOOK,
140216615Slstewart	    M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT));
141216615Slstewart
142216615Slstewart	if (hhk == NULL)
143216615Slstewart		return (ENOMEM);
144216615Slstewart
145216615Slstewart	hhk->hhk_helper = hki->hook_helper;
146216615Slstewart	hhk->hhk_func = hki->hook_func;
147216615Slstewart	hhk->hhk_udata = hki->hook_udata;
148216615Slstewart
149216615Slstewart	HHH_WLOCK(hhh);
150216615Slstewart	STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) {
151216615Slstewart		if (tmp->hhk_func == hki->hook_func &&
152216615Slstewart		    tmp->hhk_udata == hki->hook_udata) {
153216615Slstewart			/* The helper hook function is already registered. */
154216615Slstewart			error = EEXIST;
155216615Slstewart			break;
156216615Slstewart		}
157216615Slstewart	}
158216615Slstewart
159216615Slstewart	if (!error) {
160216615Slstewart		STAILQ_INSERT_TAIL(&hhh->hhh_hooks, hhk, hhk_next);
161216615Slstewart		hhh->hhh_nhooks++;
162217248Slstewart	} else
163216615Slstewart		free(hhk, M_HHOOK);
164216615Slstewart
165216615Slstewart	HHH_WUNLOCK(hhh);
166216615Slstewart
167216615Slstewart	return (error);
168216615Slstewart}
169216615Slstewart
170216615Slstewart/*
171251770Slstewart * Register a helper hook function with a helper hook point (including all
172251770Slstewart * virtual instances of the hook point if it is virtualised).
173251770Slstewart *
174251770Slstewart * The logic is unfortunately far more complex than for
175251770Slstewart * hhook_remove_hook_lookup() because hhook_add_hook() can call malloc() with
176251770Slstewart * M_WAITOK and thus we cannot call hhook_add_hook() with the
177251770Slstewart * hhook_head_list_lock held.
178251770Slstewart *
179251770Slstewart * The logic assembles an array of hhook_head structs that correspond to the
180251770Slstewart * helper hook point being hooked and bumps the refcount on each (all done with
181251770Slstewart * the hhook_head_list_lock held). The hhook_head_list_lock is then dropped, and
182251770Slstewart * hhook_add_hook() is called and the refcount dropped for each hhook_head
183251770Slstewart * struct in the array.
184216615Slstewart */
185216615Slstewartint
186216615Slstewarthhook_add_hook_lookup(struct hookinfo *hki, uint32_t flags)
187216615Slstewart{
188251770Slstewart	struct hhook_head **heads_to_hook, *hhh;
189251770Slstewart	int error, i, n_heads_to_hook;
190216615Slstewart
191251770Slstewarttryagain:
192251770Slstewart	error = i = 0;
193251770Slstewart	/*
194251770Slstewart	 * Accessing n_hhookheads without hhook_head_list_lock held opens up a
195251770Slstewart	 * race with hhook_head_register() which we are unlikely to lose, but
196251770Slstewart	 * nonetheless have to cope with - hence the complex goto logic.
197251770Slstewart	 */
198251770Slstewart	n_heads_to_hook = n_hhookheads;
199251770Slstewart	heads_to_hook = malloc(n_heads_to_hook * sizeof(struct hhook_head *),
200251770Slstewart	    M_HHOOK, flags & HHOOK_WAITOK ? M_WAITOK : M_NOWAIT);
201251770Slstewart	if (heads_to_hook == NULL)
202251770Slstewart		return (ENOMEM);
203216615Slstewart
204251770Slstewart	HHHLIST_LOCK();
205251770Slstewart	LIST_FOREACH(hhh, &hhook_head_list, hhh_next) {
206251770Slstewart		if (hhh->hhh_type == hki->hook_type &&
207251770Slstewart		    hhh->hhh_id == hki->hook_id) {
208251770Slstewart			if (i < n_heads_to_hook) {
209251770Slstewart				heads_to_hook[i] = hhh;
210251770Slstewart				refcount_acquire(&heads_to_hook[i]->hhh_refcount);
211251770Slstewart				i++;
212251770Slstewart			} else {
213251770Slstewart				/*
214251770Slstewart				 * We raced with hhook_head_register() which
215251770Slstewart				 * inserted a hhook_head that we need to hook
216251770Slstewart				 * but did not malloc space for. Abort this run
217251770Slstewart				 * and try again.
218251770Slstewart				 */
219251770Slstewart				for (i--; i >= 0; i--)
220251770Slstewart					refcount_release(&heads_to_hook[i]->hhh_refcount);
221251770Slstewart				free(heads_to_hook, M_HHOOK);
222251770Slstewart				HHHLIST_UNLOCK();
223251770Slstewart				goto tryagain;
224251770Slstewart			}
225251770Slstewart		}
226251770Slstewart	}
227251770Slstewart	HHHLIST_UNLOCK();
228216615Slstewart
229251770Slstewart	for (i--; i >= 0; i--) {
230251770Slstewart		if (!error)
231251770Slstewart			error = hhook_add_hook(heads_to_hook[i], hki, flags);
232251770Slstewart		refcount_release(&heads_to_hook[i]->hhh_refcount);
233251770Slstewart	}
234216615Slstewart
235251770Slstewart	free(heads_to_hook, M_HHOOK);
236251770Slstewart
237216615Slstewart	return (error);
238216615Slstewart}
239216615Slstewart
240216615Slstewart/*
241216615Slstewart * Remove a helper hook function from a helper hook point.
242216615Slstewart */
243216615Slstewartint
244216615Slstewarthhook_remove_hook(struct hhook_head *hhh, struct hookinfo *hki)
245216615Slstewart{
246216615Slstewart	struct hhook *tmp;
247216615Slstewart
248216615Slstewart	if (hhh == NULL)
249216615Slstewart		return (ENOENT);
250216615Slstewart
251216615Slstewart	HHH_WLOCK(hhh);
252216615Slstewart	STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) {
253216615Slstewart		if (tmp->hhk_func == hki->hook_func &&
254216615Slstewart		    tmp->hhk_udata == hki->hook_udata) {
255216615Slstewart			STAILQ_REMOVE(&hhh->hhh_hooks, tmp, hhook, hhk_next);
256216615Slstewart			free(tmp, M_HHOOK);
257216615Slstewart			hhh->hhh_nhooks--;
258216615Slstewart			break;
259216615Slstewart		}
260216615Slstewart	}
261216615Slstewart	HHH_WUNLOCK(hhh);
262216615Slstewart
263216615Slstewart	return (0);
264216615Slstewart}
265216615Slstewart
266216615Slstewart/*
267251770Slstewart * Remove a helper hook function from a helper hook point (including all
268251770Slstewart * virtual instances of the hook point if it is virtualised).
269216615Slstewart */
270216615Slstewartint
271216615Slstewarthhook_remove_hook_lookup(struct hookinfo *hki)
272216615Slstewart{
273216615Slstewart	struct hhook_head *hhh;
274216615Slstewart
275251770Slstewart	HHHLIST_LOCK();
276251770Slstewart	LIST_FOREACH(hhh, &hhook_head_list, hhh_next) {
277251770Slstewart		if (hhh->hhh_type == hki->hook_type &&
278251770Slstewart		    hhh->hhh_id == hki->hook_id)
279251770Slstewart			hhook_remove_hook(hhh, hki);
280251770Slstewart	}
281251770Slstewart	HHHLIST_UNLOCK();
282216615Slstewart
283216615Slstewart	return (0);
284216615Slstewart}
285216615Slstewart
286216615Slstewart/*
287216615Slstewart * Register a new helper hook point.
288216615Slstewart */
289216615Slstewartint
290216615Slstewarthhook_head_register(int32_t hhook_type, int32_t hhook_id, struct hhook_head **hhh,
291216615Slstewart    uint32_t flags)
292216615Slstewart{
293216615Slstewart	struct hhook_head *tmphhh;
294216615Slstewart
295216615Slstewart	tmphhh = hhook_head_get(hhook_type, hhook_id);
296216615Slstewart
297216615Slstewart	if (tmphhh != NULL) {
298216615Slstewart		/* Hook point previously registered. */
299216615Slstewart		hhook_head_release(tmphhh);
300216615Slstewart		return (EEXIST);
301216615Slstewart	}
302216615Slstewart
303216615Slstewart	tmphhh = malloc(sizeof(struct hhook_head), M_HHOOK,
304216615Slstewart	    M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT));
305216615Slstewart
306216615Slstewart	if (tmphhh == NULL)
307216615Slstewart		return (ENOMEM);
308216615Slstewart
309216615Slstewart	tmphhh->hhh_type = hhook_type;
310216615Slstewart	tmphhh->hhh_id = hhook_id;
311216615Slstewart	tmphhh->hhh_nhooks = 0;
312216615Slstewart	STAILQ_INIT(&tmphhh->hhh_hooks);
313216615Slstewart	HHH_LOCK_INIT(tmphhh);
314216615Slstewart
315251725Slstewart	if (hhh != NULL) {
316216615Slstewart		refcount_init(&tmphhh->hhh_refcount, 1);
317251725Slstewart		*hhh = tmphhh;
318251725Slstewart	} else
319216615Slstewart		refcount_init(&tmphhh->hhh_refcount, 0);
320216615Slstewart
321251732Slstewart	HHHLIST_LOCK();
322216615Slstewart	if (flags & HHOOK_HEADISINVNET) {
323216615Slstewart		tmphhh->hhh_flags |= HHH_ISINVNET;
324251752Slstewart#ifdef VIMAGE
325251732Slstewart		KASSERT(curvnet != NULL, ("curvnet is NULL"));
326251732Slstewart		tmphhh->hhh_vid = (uintptr_t)curvnet;
327251732Slstewart		LIST_INSERT_HEAD(&V_hhook_vhead_list, tmphhh, hhh_vnext);
328251752Slstewart#endif
329216615Slstewart	}
330251732Slstewart	LIST_INSERT_HEAD(&hhook_head_list, tmphhh, hhh_next);
331251770Slstewart	n_hhookheads++;
332251732Slstewart	HHHLIST_UNLOCK();
333216615Slstewart
334216615Slstewart	return (0);
335216615Slstewart}
336216615Slstewart
337216615Slstewartstatic void
338216615Slstewarthhook_head_destroy(struct hhook_head *hhh)
339216615Slstewart{
340216615Slstewart	struct hhook *tmp, *tmp2;
341216615Slstewart
342216615Slstewart	HHHLIST_LOCK_ASSERT();
343251770Slstewart	KASSERT(n_hhookheads > 0, ("n_hhookheads should be > 0"));
344216615Slstewart
345216615Slstewart	LIST_REMOVE(hhh, hhh_next);
346251752Slstewart#ifdef VIMAGE
347251732Slstewart	if (hhook_head_is_virtualised(hhh) == HHOOK_HEADISINVNET)
348251732Slstewart		LIST_REMOVE(hhh, hhh_vnext);
349251752Slstewart#endif
350216615Slstewart	HHH_WLOCK(hhh);
351216615Slstewart	STAILQ_FOREACH_SAFE(tmp, &hhh->hhh_hooks, hhk_next, tmp2)
352216615Slstewart		free(tmp, M_HHOOK);
353216615Slstewart	HHH_WUNLOCK(hhh);
354216615Slstewart	HHH_LOCK_DESTROY(hhh);
355216615Slstewart	free(hhh, M_HHOOK);
356251770Slstewart	n_hhookheads--;
357216615Slstewart}
358216615Slstewart
359216615Slstewart/*
360216615Slstewart * Remove a helper hook point.
361216615Slstewart */
362216615Slstewartint
363216615Slstewarthhook_head_deregister(struct hhook_head *hhh)
364216615Slstewart{
365216615Slstewart	int error;
366216615Slstewart
367216615Slstewart	error = 0;
368216615Slstewart
369216615Slstewart	HHHLIST_LOCK();
370216615Slstewart	if (hhh == NULL)
371216615Slstewart		error = ENOENT;
372216615Slstewart	else if (hhh->hhh_refcount > 1)
373216615Slstewart		error = EBUSY;
374216615Slstewart	else
375216615Slstewart		hhook_head_destroy(hhh);
376216615Slstewart	HHHLIST_UNLOCK();
377216615Slstewart
378216615Slstewart	return (error);
379216615Slstewart}
380216615Slstewart
381216615Slstewart/*
382216615Slstewart * Remove a helper hook point via a hhook_head lookup.
383216615Slstewart */
384216615Slstewartint
385216615Slstewarthhook_head_deregister_lookup(int32_t hhook_type, int32_t hhook_id)
386216615Slstewart{
387216615Slstewart	struct hhook_head *hhh;
388216615Slstewart	int error;
389216615Slstewart
390216615Slstewart	hhh = hhook_head_get(hhook_type, hhook_id);
391216615Slstewart	error = hhook_head_deregister(hhh);
392216615Slstewart
393216615Slstewart	if (error == EBUSY)
394216615Slstewart		hhook_head_release(hhh);
395216615Slstewart
396216615Slstewart	return (error);
397216615Slstewart}
398216615Slstewart
399216615Slstewart/*
400216615Slstewart * Lookup and return the hhook_head struct associated with the specified type
401216615Slstewart * and id, or NULL if not found. If found, the hhook_head's refcount is bumped.
402216615Slstewart */
403216615Slstewartstruct hhook_head *
404216615Slstewarthhook_head_get(int32_t hhook_type, int32_t hhook_id)
405216615Slstewart{
406216615Slstewart	struct hhook_head *hhh;
407216615Slstewart
408216615Slstewart	HHHLIST_LOCK();
409251732Slstewart	LIST_FOREACH(hhh, &hhook_head_list, hhh_next) {
410216615Slstewart		if (hhh->hhh_type == hhook_type && hhh->hhh_id == hhook_id) {
411251752Slstewart#ifdef VIMAGE
412251732Slstewart			if (hhook_head_is_virtualised(hhh) ==
413251732Slstewart			    HHOOK_HEADISINVNET) {
414251732Slstewart				KASSERT(curvnet != NULL, ("curvnet is NULL"));
415251732Slstewart				if (hhh->hhh_vid != (uintptr_t)curvnet)
416251732Slstewart					continue;
417251732Slstewart			}
418251752Slstewart#endif
419216615Slstewart			refcount_acquire(&hhh->hhh_refcount);
420217248Slstewart			break;
421216615Slstewart		}
422216615Slstewart	}
423216615Slstewart	HHHLIST_UNLOCK();
424216615Slstewart
425217248Slstewart	return (hhh);
426216615Slstewart}
427216615Slstewart
428216615Slstewartvoid
429216615Slstewarthhook_head_release(struct hhook_head *hhh)
430216615Slstewart{
431216615Slstewart
432216615Slstewart	refcount_release(&hhh->hhh_refcount);
433216615Slstewart}
434216615Slstewart
435216615Slstewart/*
436216615Slstewart * Check the hhook_head private flags and return the appropriate public
437216615Slstewart * representation of the flag to the caller. The function is implemented in a
438216615Slstewart * way that allows us to cope with other subsystems becoming virtualised in the
439216615Slstewart * future.
440216615Slstewart */
441216615Slstewartuint32_t
442216615Slstewarthhook_head_is_virtualised(struct hhook_head *hhh)
443216615Slstewart{
444216615Slstewart	uint32_t ret;
445216615Slstewart
446217250Slstewart	ret = 0;
447216615Slstewart
448217250Slstewart	if (hhh != NULL) {
449217250Slstewart		if (hhh->hhh_flags & HHH_ISINVNET)
450217250Slstewart			ret = HHOOK_HEADISINVNET;
451217250Slstewart	}
452216615Slstewart
453216615Slstewart	return (ret);
454216615Slstewart}
455216615Slstewart
456216615Slstewartuint32_t
457216615Slstewarthhook_head_is_virtualised_lookup(int32_t hook_type, int32_t hook_id)
458216615Slstewart{
459216615Slstewart	struct hhook_head *hhh;
460216615Slstewart	uint32_t ret;
461216615Slstewart
462216615Slstewart	hhh = hhook_head_get(hook_type, hook_id);
463216615Slstewart
464216615Slstewart	if (hhh == NULL)
465216615Slstewart		return (0);
466216615Slstewart
467216615Slstewart	ret = hhook_head_is_virtualised(hhh);
468216615Slstewart	hhook_head_release(hhh);
469216615Slstewart
470216615Slstewart	return (ret);
471216615Slstewart}
472216615Slstewart
473216615Slstewart/*
474216615Slstewart * Vnet created and being initialised.
475216615Slstewart */
476216615Slstewartstatic void
477216615Slstewarthhook_vnet_init(const void *unused __unused)
478216615Slstewart{
479216615Slstewart
480251732Slstewart	LIST_INIT(&V_hhook_vhead_list);
481216615Slstewart}
482216615Slstewart
483216615Slstewart/*
484216615Slstewart * Vnet being torn down and destroyed.
485216615Slstewart */
486216615Slstewartstatic void
487216615Slstewarthhook_vnet_uninit(const void *unused __unused)
488216615Slstewart{
489216615Slstewart	struct hhook_head *hhh, *tmphhh;
490216615Slstewart
491216615Slstewart	/*
492216615Slstewart	 * If subsystems which export helper hook points use the hhook KPI
493216615Slstewart	 * correctly, the loop below should have no work to do because the
494216615Slstewart	 * subsystem should have already called hhook_head_deregister().
495216615Slstewart	 */
496216615Slstewart	HHHLIST_LOCK();
497251732Slstewart	LIST_FOREACH_SAFE(hhh, &V_hhook_vhead_list, hhh_vnext, tmphhh) {
498216615Slstewart		printf("%s: hhook_head type=%d, id=%d cleanup required\n",
499216615Slstewart		    __func__, hhh->hhh_type, hhh->hhh_id);
500216615Slstewart		hhook_head_destroy(hhh);
501216615Slstewart	}
502216615Slstewart	HHHLIST_UNLOCK();
503216615Slstewart}
504216615Slstewart
505216615Slstewart
506216615Slstewart/*
507251732Slstewart * When a vnet is created and being initialised, init the V_hhook_vhead_list.
508216615Slstewart */
509216615SlstewartVNET_SYSINIT(hhook_vnet_init, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST,
510216615Slstewart    hhook_vnet_init, NULL);
511216615Slstewart
512216615Slstewart/*
513216615Slstewart * The hhook KPI provides a mechanism for subsystems which export helper hook
514216615Slstewart * points to clean up on vnet tear down, but in case the KPI is misused,
515216615Slstewart * provide a function to clean up and free memory for a vnet being destroyed.
516216615Slstewart */
517216615SlstewartVNET_SYSUNINIT(hhook_vnet_uninit, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST,
518216615Slstewart    hhook_vnet_uninit, NULL);
519