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