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