1a8d61afdSLawrence Stewart /*- 2a8d61afdSLawrence Stewart * Copyright (c) 2010 Lawrence Stewart <lstewart@freebsd.org> 3a8d61afdSLawrence Stewart * Copyright (c) 2010 The FreeBSD Foundation 4a8d61afdSLawrence Stewart * All rights reserved. 5a8d61afdSLawrence Stewart * 6a8d61afdSLawrence Stewart * This software was developed by Lawrence Stewart while studying at the Centre 7891b8ed4SLawrence Stewart * for Advanced Internet Architectures, Swinburne University of Technology, 8891b8ed4SLawrence Stewart * made possible in part by grants from the FreeBSD Foundation and Cisco 9891b8ed4SLawrence Stewart * University Research Program Fund at Community Foundation Silicon Valley. 10a8d61afdSLawrence Stewart * 11a8d61afdSLawrence Stewart * Portions of this software were developed at the Centre for Advanced 12a8d61afdSLawrence Stewart * Internet Architectures, Swinburne University of Technology, Melbourne, 13a8d61afdSLawrence Stewart * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. 14a8d61afdSLawrence Stewart * 15a8d61afdSLawrence Stewart * Redistribution and use in source and binary forms, with or without 16a8d61afdSLawrence Stewart * modification, are permitted provided that the following conditions 17a8d61afdSLawrence Stewart * are met: 18a8d61afdSLawrence Stewart * 1. Redistributions of source code must retain the above copyright 19a8d61afdSLawrence Stewart * notice, this list of conditions and the following disclaimer. 20a8d61afdSLawrence Stewart * 2. Redistributions in binary form must reproduce the above copyright 21a8d61afdSLawrence Stewart * notice, this list of conditions and the following disclaimer in the 22a8d61afdSLawrence Stewart * documentation and/or other materials provided with the distribution. 23a8d61afdSLawrence Stewart * 24a8d61afdSLawrence Stewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25a8d61afdSLawrence Stewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26a8d61afdSLawrence Stewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27a8d61afdSLawrence Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28a8d61afdSLawrence Stewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29a8d61afdSLawrence Stewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30a8d61afdSLawrence Stewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31a8d61afdSLawrence Stewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32a8d61afdSLawrence Stewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33a8d61afdSLawrence Stewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34a8d61afdSLawrence Stewart * SUCH DAMAGE. 35a8d61afdSLawrence Stewart */ 36a8d61afdSLawrence Stewart 37a8d61afdSLawrence Stewart #include <sys/cdefs.h> 38a8d61afdSLawrence Stewart __FBSDID("$FreeBSD$"); 39a8d61afdSLawrence Stewart 40a8d61afdSLawrence Stewart #include <sys/param.h> 41a8d61afdSLawrence Stewart #include <sys/kernel.h> 42a8d61afdSLawrence Stewart #include <sys/hhook.h> 43a8d61afdSLawrence Stewart #include <sys/khelp.h> 44a8d61afdSLawrence Stewart #include <sys/malloc.h> 45a8d61afdSLawrence Stewart #include <sys/module.h> 46a8d61afdSLawrence Stewart #include <sys/module_khelp.h> 47a8d61afdSLawrence Stewart #include <sys/osd.h> 48a8d61afdSLawrence Stewart #include <sys/queue.h> 49a8d61afdSLawrence Stewart #include <sys/refcount.h> 50a8d61afdSLawrence Stewart #include <sys/systm.h> 51a8d61afdSLawrence Stewart 52a8d61afdSLawrence Stewart #include <net/vnet.h> 53a8d61afdSLawrence Stewart 54a8d61afdSLawrence Stewart struct hhook { 55a8d61afdSLawrence Stewart hhook_func_t hhk_func; 56a8d61afdSLawrence Stewart struct helper *hhk_helper; 57a8d61afdSLawrence Stewart void *hhk_udata; 58a8d61afdSLawrence Stewart STAILQ_ENTRY(hhook) hhk_next; 59a8d61afdSLawrence Stewart }; 60a8d61afdSLawrence Stewart 616bed196cSSergey Kandaurov static MALLOC_DEFINE(M_HHOOK, "hhook", "Helper hooks are linked off hhook_head lists"); 62a8d61afdSLawrence Stewart 63a8d61afdSLawrence Stewart LIST_HEAD(hhookheadhead, hhook_head); 64*601d4c75SLawrence Stewart struct hhookheadhead hhook_head_list; 65*601d4c75SLawrence Stewart VNET_DEFINE(struct hhookheadhead, hhook_vhead_list); 66*601d4c75SLawrence Stewart #define V_hhook_vhead_list VNET(hhook_vhead_list) 67a8d61afdSLawrence Stewart 68a8d61afdSLawrence Stewart static struct mtx hhook_head_list_lock; 69a8d61afdSLawrence Stewart MTX_SYSINIT(hhookheadlistlock, &hhook_head_list_lock, "hhook_head list lock", 70a8d61afdSLawrence Stewart MTX_DEF); 71a8d61afdSLawrence Stewart 72a8d61afdSLawrence Stewart /* Private function prototypes. */ 73a8d61afdSLawrence Stewart static void hhook_head_destroy(struct hhook_head *hhh); 74a8d61afdSLawrence Stewart 75a8d61afdSLawrence Stewart #define HHHLIST_LOCK() mtx_lock(&hhook_head_list_lock) 76a8d61afdSLawrence Stewart #define HHHLIST_UNLOCK() mtx_unlock(&hhook_head_list_lock) 77a8d61afdSLawrence Stewart #define HHHLIST_LOCK_ASSERT() mtx_assert(&hhook_head_list_lock, MA_OWNED) 78a8d61afdSLawrence Stewart 79a8d61afdSLawrence Stewart #define HHH_LOCK_INIT(hhh) rm_init(&(hhh)->hhh_lock, "hhook_head rm lock") 80a8d61afdSLawrence Stewart #define HHH_LOCK_DESTROY(hhh) rm_destroy(&(hhh)->hhh_lock) 81a8d61afdSLawrence Stewart #define HHH_WLOCK(hhh) rm_wlock(&(hhh)->hhh_lock) 82a8d61afdSLawrence Stewart #define HHH_WUNLOCK(hhh) rm_wunlock(&(hhh)->hhh_lock) 83a8d61afdSLawrence Stewart #define HHH_RLOCK(hhh, rmpt) rm_rlock(&(hhh)->hhh_lock, (rmpt)) 84a8d61afdSLawrence Stewart #define HHH_RUNLOCK(hhh, rmpt) rm_runlock(&(hhh)->hhh_lock, (rmpt)) 85a8d61afdSLawrence Stewart 86a8d61afdSLawrence Stewart /* 87a8d61afdSLawrence Stewart * Run all helper hook functions for a given hook point. 88a8d61afdSLawrence Stewart */ 89a8d61afdSLawrence Stewart void 90a8d61afdSLawrence Stewart hhook_run_hooks(struct hhook_head *hhh, void *ctx_data, struct osd *hosd) 91a8d61afdSLawrence Stewart { 92a8d61afdSLawrence Stewart struct hhook *hhk; 93a8d61afdSLawrence Stewart void *hdata; 94a8d61afdSLawrence Stewart struct rm_priotracker rmpt; 95a8d61afdSLawrence Stewart 96a8d61afdSLawrence Stewart KASSERT(hhh->hhh_refcount > 0, ("hhook_head %p refcount is 0", hhh)); 97a8d61afdSLawrence Stewart 98a8d61afdSLawrence Stewart HHH_RLOCK(hhh, &rmpt); 99a8d61afdSLawrence Stewart STAILQ_FOREACH(hhk, &hhh->hhh_hooks, hhk_next) { 100a8d61afdSLawrence Stewart if (hhk->hhk_helper->h_flags & HELPER_NEEDS_OSD) { 101a8d61afdSLawrence Stewart hdata = osd_get(OSD_KHELP, hosd, hhk->hhk_helper->h_id); 102a8d61afdSLawrence Stewart if (hdata == NULL) 103a8d61afdSLawrence Stewart continue; 104a8d61afdSLawrence Stewart } else 105a8d61afdSLawrence Stewart hdata = NULL; 106a8d61afdSLawrence Stewart 107a8d61afdSLawrence Stewart /* 108a8d61afdSLawrence Stewart * XXXLAS: We currently ignore the int returned by the hook, 109a8d61afdSLawrence Stewart * but will likely want to handle it in future to allow hhook to 110a8d61afdSLawrence Stewart * be used like pfil and effect changes at the hhook calling 111a8d61afdSLawrence Stewart * site e.g. we could define a new hook type of HHOOK_TYPE_PFIL 112a8d61afdSLawrence Stewart * and standardise what particular return values mean and set 113a8d61afdSLawrence Stewart * the context data to pass exactly the same information as pfil 114a8d61afdSLawrence Stewart * hooks currently receive, thus replicating pfil with hhook. 115a8d61afdSLawrence Stewart */ 116a8d61afdSLawrence Stewart hhk->hhk_func(hhh->hhh_type, hhh->hhh_id, hhk->hhk_udata, 117a8d61afdSLawrence Stewart ctx_data, hdata, hosd); 118a8d61afdSLawrence Stewart } 119a8d61afdSLawrence Stewart HHH_RUNLOCK(hhh, &rmpt); 120a8d61afdSLawrence Stewart } 121a8d61afdSLawrence Stewart 122a8d61afdSLawrence Stewart /* 123a8d61afdSLawrence Stewart * Register a new helper hook function with a helper hook point. 124a8d61afdSLawrence Stewart */ 125a8d61afdSLawrence Stewart int 126a8d61afdSLawrence Stewart hhook_add_hook(struct hhook_head *hhh, struct hookinfo *hki, uint32_t flags) 127a8d61afdSLawrence Stewart { 128a8d61afdSLawrence Stewart struct hhook *hhk, *tmp; 129a8d61afdSLawrence Stewart int error; 130a8d61afdSLawrence Stewart 131a8d61afdSLawrence Stewart error = 0; 132a8d61afdSLawrence Stewart 133a8d61afdSLawrence Stewart if (hhh == NULL) 134a8d61afdSLawrence Stewart return (ENOENT); 135a8d61afdSLawrence Stewart 136a8d61afdSLawrence Stewart hhk = malloc(sizeof(struct hhook), M_HHOOK, 137a8d61afdSLawrence Stewart M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); 138a8d61afdSLawrence Stewart 139a8d61afdSLawrence Stewart if (hhk == NULL) 140a8d61afdSLawrence Stewart return (ENOMEM); 141a8d61afdSLawrence Stewart 142a8d61afdSLawrence Stewart hhk->hhk_helper = hki->hook_helper; 143a8d61afdSLawrence Stewart hhk->hhk_func = hki->hook_func; 144a8d61afdSLawrence Stewart hhk->hhk_udata = hki->hook_udata; 145a8d61afdSLawrence Stewart 146a8d61afdSLawrence Stewart HHH_WLOCK(hhh); 147a8d61afdSLawrence Stewart STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) { 148a8d61afdSLawrence Stewart if (tmp->hhk_func == hki->hook_func && 149a8d61afdSLawrence Stewart tmp->hhk_udata == hki->hook_udata) { 150a8d61afdSLawrence Stewart /* The helper hook function is already registered. */ 151a8d61afdSLawrence Stewart error = EEXIST; 152a8d61afdSLawrence Stewart break; 153a8d61afdSLawrence Stewart } 154a8d61afdSLawrence Stewart } 155a8d61afdSLawrence Stewart 156a8d61afdSLawrence Stewart if (!error) { 157a8d61afdSLawrence Stewart STAILQ_INSERT_TAIL(&hhh->hhh_hooks, hhk, hhk_next); 158a8d61afdSLawrence Stewart hhh->hhh_nhooks++; 159188d9a49SLawrence Stewart } else 160a8d61afdSLawrence Stewart free(hhk, M_HHOOK); 161a8d61afdSLawrence Stewart 162a8d61afdSLawrence Stewart HHH_WUNLOCK(hhh); 163a8d61afdSLawrence Stewart 164a8d61afdSLawrence Stewart return (error); 165a8d61afdSLawrence Stewart } 166a8d61afdSLawrence Stewart 167a8d61afdSLawrence Stewart /* 168a8d61afdSLawrence Stewart * Lookup a helper hook point and register a new helper hook function with it. 169a8d61afdSLawrence Stewart */ 170a8d61afdSLawrence Stewart int 171a8d61afdSLawrence Stewart hhook_add_hook_lookup(struct hookinfo *hki, uint32_t flags) 172a8d61afdSLawrence Stewart { 173a8d61afdSLawrence Stewart struct hhook_head *hhh; 174a8d61afdSLawrence Stewart int error; 175a8d61afdSLawrence Stewart 176a8d61afdSLawrence Stewart hhh = hhook_head_get(hki->hook_type, hki->hook_id); 177a8d61afdSLawrence Stewart 178a8d61afdSLawrence Stewart if (hhh == NULL) 179a8d61afdSLawrence Stewart return (ENOENT); 180a8d61afdSLawrence Stewart 181a8d61afdSLawrence Stewart error = hhook_add_hook(hhh, hki, flags); 182a8d61afdSLawrence Stewart hhook_head_release(hhh); 183a8d61afdSLawrence Stewart 184a8d61afdSLawrence Stewart return (error); 185a8d61afdSLawrence Stewart } 186a8d61afdSLawrence Stewart 187a8d61afdSLawrence Stewart /* 188a8d61afdSLawrence Stewart * Remove a helper hook function from a helper hook point. 189a8d61afdSLawrence Stewart */ 190a8d61afdSLawrence Stewart int 191a8d61afdSLawrence Stewart hhook_remove_hook(struct hhook_head *hhh, struct hookinfo *hki) 192a8d61afdSLawrence Stewart { 193a8d61afdSLawrence Stewart struct hhook *tmp; 194a8d61afdSLawrence Stewart 195a8d61afdSLawrence Stewart if (hhh == NULL) 196a8d61afdSLawrence Stewart return (ENOENT); 197a8d61afdSLawrence Stewart 198a8d61afdSLawrence Stewart HHH_WLOCK(hhh); 199a8d61afdSLawrence Stewart STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) { 200a8d61afdSLawrence Stewart if (tmp->hhk_func == hki->hook_func && 201a8d61afdSLawrence Stewart tmp->hhk_udata == hki->hook_udata) { 202a8d61afdSLawrence Stewart STAILQ_REMOVE(&hhh->hhh_hooks, tmp, hhook, hhk_next); 203a8d61afdSLawrence Stewart free(tmp, M_HHOOK); 204a8d61afdSLawrence Stewart hhh->hhh_nhooks--; 205a8d61afdSLawrence Stewart break; 206a8d61afdSLawrence Stewart } 207a8d61afdSLawrence Stewart } 208a8d61afdSLawrence Stewart HHH_WUNLOCK(hhh); 209a8d61afdSLawrence Stewart 210a8d61afdSLawrence Stewart return (0); 211a8d61afdSLawrence Stewart } 212a8d61afdSLawrence Stewart 213a8d61afdSLawrence Stewart /* 214a8d61afdSLawrence Stewart * Lookup a helper hook point and remove a helper hook function from it. 215a8d61afdSLawrence Stewart */ 216a8d61afdSLawrence Stewart int 217a8d61afdSLawrence Stewart hhook_remove_hook_lookup(struct hookinfo *hki) 218a8d61afdSLawrence Stewart { 219a8d61afdSLawrence Stewart struct hhook_head *hhh; 220a8d61afdSLawrence Stewart 221a8d61afdSLawrence Stewart hhh = hhook_head_get(hki->hook_type, hki->hook_id); 222a8d61afdSLawrence Stewart 223a8d61afdSLawrence Stewart if (hhh == NULL) 224a8d61afdSLawrence Stewart return (ENOENT); 225a8d61afdSLawrence Stewart 226a8d61afdSLawrence Stewart hhook_remove_hook(hhh, hki); 227a8d61afdSLawrence Stewart hhook_head_release(hhh); 228a8d61afdSLawrence Stewart 229a8d61afdSLawrence Stewart return (0); 230a8d61afdSLawrence Stewart } 231a8d61afdSLawrence Stewart 232a8d61afdSLawrence Stewart /* 233a8d61afdSLawrence Stewart * Register a new helper hook point. 234a8d61afdSLawrence Stewart */ 235a8d61afdSLawrence Stewart int 236a8d61afdSLawrence Stewart hhook_head_register(int32_t hhook_type, int32_t hhook_id, struct hhook_head **hhh, 237a8d61afdSLawrence Stewart uint32_t flags) 238a8d61afdSLawrence Stewart { 239a8d61afdSLawrence Stewart struct hhook_head *tmphhh; 240a8d61afdSLawrence Stewart 241a8d61afdSLawrence Stewart tmphhh = hhook_head_get(hhook_type, hhook_id); 242a8d61afdSLawrence Stewart 243a8d61afdSLawrence Stewart if (tmphhh != NULL) { 244a8d61afdSLawrence Stewart /* Hook point previously registered. */ 245a8d61afdSLawrence Stewart hhook_head_release(tmphhh); 246a8d61afdSLawrence Stewart return (EEXIST); 247a8d61afdSLawrence Stewart } 248a8d61afdSLawrence Stewart 249a8d61afdSLawrence Stewart tmphhh = malloc(sizeof(struct hhook_head), M_HHOOK, 250a8d61afdSLawrence Stewart M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); 251a8d61afdSLawrence Stewart 252a8d61afdSLawrence Stewart if (tmphhh == NULL) 253a8d61afdSLawrence Stewart return (ENOMEM); 254a8d61afdSLawrence Stewart 255a8d61afdSLawrence Stewart tmphhh->hhh_type = hhook_type; 256a8d61afdSLawrence Stewart tmphhh->hhh_id = hhook_id; 257a8d61afdSLawrence Stewart tmphhh->hhh_nhooks = 0; 258a8d61afdSLawrence Stewart STAILQ_INIT(&tmphhh->hhh_hooks); 259a8d61afdSLawrence Stewart HHH_LOCK_INIT(tmphhh); 260a8d61afdSLawrence Stewart 26186241d89SLawrence Stewart if (hhh != NULL) { 262a8d61afdSLawrence Stewart refcount_init(&tmphhh->hhh_refcount, 1); 26386241d89SLawrence Stewart *hhh = tmphhh; 26486241d89SLawrence Stewart } else 265a8d61afdSLawrence Stewart refcount_init(&tmphhh->hhh_refcount, 0); 266a8d61afdSLawrence Stewart 267*601d4c75SLawrence Stewart HHHLIST_LOCK(); 268a8d61afdSLawrence Stewart if (flags & HHOOK_HEADISINVNET) { 269a8d61afdSLawrence Stewart tmphhh->hhh_flags |= HHH_ISINVNET; 270*601d4c75SLawrence Stewart KASSERT(curvnet != NULL, ("curvnet is NULL")); 271*601d4c75SLawrence Stewart tmphhh->hhh_vid = (uintptr_t)curvnet; 272*601d4c75SLawrence Stewart LIST_INSERT_HEAD(&V_hhook_vhead_list, tmphhh, hhh_vnext); 273a8d61afdSLawrence Stewart } 274*601d4c75SLawrence Stewart LIST_INSERT_HEAD(&hhook_head_list, tmphhh, hhh_next); 275*601d4c75SLawrence Stewart HHHLIST_UNLOCK(); 276a8d61afdSLawrence Stewart 277a8d61afdSLawrence Stewart return (0); 278a8d61afdSLawrence Stewart } 279a8d61afdSLawrence Stewart 280a8d61afdSLawrence Stewart static void 281a8d61afdSLawrence Stewart hhook_head_destroy(struct hhook_head *hhh) 282a8d61afdSLawrence Stewart { 283a8d61afdSLawrence Stewart struct hhook *tmp, *tmp2; 284a8d61afdSLawrence Stewart 285a8d61afdSLawrence Stewart HHHLIST_LOCK_ASSERT(); 286a8d61afdSLawrence Stewart 287a8d61afdSLawrence Stewart LIST_REMOVE(hhh, hhh_next); 288*601d4c75SLawrence Stewart if (hhook_head_is_virtualised(hhh) == HHOOK_HEADISINVNET) 289*601d4c75SLawrence Stewart LIST_REMOVE(hhh, hhh_vnext); 290a8d61afdSLawrence Stewart HHH_WLOCK(hhh); 291a8d61afdSLawrence Stewart STAILQ_FOREACH_SAFE(tmp, &hhh->hhh_hooks, hhk_next, tmp2) 292a8d61afdSLawrence Stewart free(tmp, M_HHOOK); 293a8d61afdSLawrence Stewart HHH_WUNLOCK(hhh); 294a8d61afdSLawrence Stewart HHH_LOCK_DESTROY(hhh); 295a8d61afdSLawrence Stewart free(hhh, M_HHOOK); 296a8d61afdSLawrence Stewart } 297a8d61afdSLawrence Stewart 298a8d61afdSLawrence Stewart /* 299a8d61afdSLawrence Stewart * Remove a helper hook point. 300a8d61afdSLawrence Stewart */ 301a8d61afdSLawrence Stewart int 302a8d61afdSLawrence Stewart hhook_head_deregister(struct hhook_head *hhh) 303a8d61afdSLawrence Stewart { 304a8d61afdSLawrence Stewart int error; 305a8d61afdSLawrence Stewart 306a8d61afdSLawrence Stewart error = 0; 307a8d61afdSLawrence Stewart 308a8d61afdSLawrence Stewart HHHLIST_LOCK(); 309a8d61afdSLawrence Stewart if (hhh == NULL) 310a8d61afdSLawrence Stewart error = ENOENT; 311a8d61afdSLawrence Stewart else if (hhh->hhh_refcount > 1) 312a8d61afdSLawrence Stewart error = EBUSY; 313a8d61afdSLawrence Stewart else 314a8d61afdSLawrence Stewart hhook_head_destroy(hhh); 315a8d61afdSLawrence Stewart HHHLIST_UNLOCK(); 316a8d61afdSLawrence Stewart 317a8d61afdSLawrence Stewart return (error); 318a8d61afdSLawrence Stewart } 319a8d61afdSLawrence Stewart 320a8d61afdSLawrence Stewart /* 321a8d61afdSLawrence Stewart * Remove a helper hook point via a hhook_head lookup. 322a8d61afdSLawrence Stewart */ 323a8d61afdSLawrence Stewart int 324a8d61afdSLawrence Stewart hhook_head_deregister_lookup(int32_t hhook_type, int32_t hhook_id) 325a8d61afdSLawrence Stewart { 326a8d61afdSLawrence Stewart struct hhook_head *hhh; 327a8d61afdSLawrence Stewart int error; 328a8d61afdSLawrence Stewart 329a8d61afdSLawrence Stewart hhh = hhook_head_get(hhook_type, hhook_id); 330a8d61afdSLawrence Stewart error = hhook_head_deregister(hhh); 331a8d61afdSLawrence Stewart 332a8d61afdSLawrence Stewart if (error == EBUSY) 333a8d61afdSLawrence Stewart hhook_head_release(hhh); 334a8d61afdSLawrence Stewart 335a8d61afdSLawrence Stewart return (error); 336a8d61afdSLawrence Stewart } 337a8d61afdSLawrence Stewart 338a8d61afdSLawrence Stewart /* 339a8d61afdSLawrence Stewart * Lookup and return the hhook_head struct associated with the specified type 340a8d61afdSLawrence Stewart * and id, or NULL if not found. If found, the hhook_head's refcount is bumped. 341a8d61afdSLawrence Stewart */ 342a8d61afdSLawrence Stewart struct hhook_head * 343a8d61afdSLawrence Stewart hhook_head_get(int32_t hhook_type, int32_t hhook_id) 344a8d61afdSLawrence Stewart { 345a8d61afdSLawrence Stewart struct hhook_head *hhh; 346a8d61afdSLawrence Stewart 347a8d61afdSLawrence Stewart HHHLIST_LOCK(); 348*601d4c75SLawrence Stewart LIST_FOREACH(hhh, &hhook_head_list, hhh_next) { 349a8d61afdSLawrence Stewart if (hhh->hhh_type == hhook_type && hhh->hhh_id == hhook_id) { 350*601d4c75SLawrence Stewart if (hhook_head_is_virtualised(hhh) == 351*601d4c75SLawrence Stewart HHOOK_HEADISINVNET) { 352*601d4c75SLawrence Stewart KASSERT(curvnet != NULL, ("curvnet is NULL")); 353*601d4c75SLawrence Stewart if (hhh->hhh_vid != (uintptr_t)curvnet) 354*601d4c75SLawrence Stewart continue; 355*601d4c75SLawrence Stewart } 356a8d61afdSLawrence Stewart refcount_acquire(&hhh->hhh_refcount); 357188d9a49SLawrence Stewart break; 358a8d61afdSLawrence Stewart } 359a8d61afdSLawrence Stewart } 360a8d61afdSLawrence Stewart HHHLIST_UNLOCK(); 361a8d61afdSLawrence Stewart 362188d9a49SLawrence Stewart return (hhh); 363a8d61afdSLawrence Stewart } 364a8d61afdSLawrence Stewart 365a8d61afdSLawrence Stewart void 366a8d61afdSLawrence Stewart hhook_head_release(struct hhook_head *hhh) 367a8d61afdSLawrence Stewart { 368a8d61afdSLawrence Stewart 369a8d61afdSLawrence Stewart refcount_release(&hhh->hhh_refcount); 370a8d61afdSLawrence Stewart } 371a8d61afdSLawrence Stewart 372a8d61afdSLawrence Stewart /* 373a8d61afdSLawrence Stewart * Check the hhook_head private flags and return the appropriate public 374a8d61afdSLawrence Stewart * representation of the flag to the caller. The function is implemented in a 375a8d61afdSLawrence Stewart * way that allows us to cope with other subsystems becoming virtualised in the 376a8d61afdSLawrence Stewart * future. 377a8d61afdSLawrence Stewart */ 378a8d61afdSLawrence Stewart uint32_t 379a8d61afdSLawrence Stewart hhook_head_is_virtualised(struct hhook_head *hhh) 380a8d61afdSLawrence Stewart { 381a8d61afdSLawrence Stewart uint32_t ret; 382a8d61afdSLawrence Stewart 3835a29e4d2SLawrence Stewart ret = 0; 384a8d61afdSLawrence Stewart 3855a29e4d2SLawrence Stewart if (hhh != NULL) { 386a8d61afdSLawrence Stewart if (hhh->hhh_flags & HHH_ISINVNET) 387a8d61afdSLawrence Stewart ret = HHOOK_HEADISINVNET; 3885a29e4d2SLawrence Stewart } 389a8d61afdSLawrence Stewart 390a8d61afdSLawrence Stewart return (ret); 391a8d61afdSLawrence Stewart } 392a8d61afdSLawrence Stewart 393a8d61afdSLawrence Stewart uint32_t 394a8d61afdSLawrence Stewart hhook_head_is_virtualised_lookup(int32_t hook_type, int32_t hook_id) 395a8d61afdSLawrence Stewart { 396a8d61afdSLawrence Stewart struct hhook_head *hhh; 397a8d61afdSLawrence Stewart uint32_t ret; 398a8d61afdSLawrence Stewart 399a8d61afdSLawrence Stewart hhh = hhook_head_get(hook_type, hook_id); 400a8d61afdSLawrence Stewart 401a8d61afdSLawrence Stewart if (hhh == NULL) 402a8d61afdSLawrence Stewart return (0); 403a8d61afdSLawrence Stewart 404a8d61afdSLawrence Stewart ret = hhook_head_is_virtualised(hhh); 405a8d61afdSLawrence Stewart hhook_head_release(hhh); 406a8d61afdSLawrence Stewart 407a8d61afdSLawrence Stewart return (ret); 408a8d61afdSLawrence Stewart } 409a8d61afdSLawrence Stewart 410a8d61afdSLawrence Stewart /* 411a8d61afdSLawrence Stewart * Vnet created and being initialised. 412a8d61afdSLawrence Stewart */ 413a8d61afdSLawrence Stewart static void 414a8d61afdSLawrence Stewart hhook_vnet_init(const void *unused __unused) 415a8d61afdSLawrence Stewart { 416a8d61afdSLawrence Stewart 417*601d4c75SLawrence Stewart LIST_INIT(&V_hhook_vhead_list); 418a8d61afdSLawrence Stewart } 419a8d61afdSLawrence Stewart 420a8d61afdSLawrence Stewart /* 421a8d61afdSLawrence Stewart * Vnet being torn down and destroyed. 422a8d61afdSLawrence Stewart */ 423a8d61afdSLawrence Stewart static void 424a8d61afdSLawrence Stewart hhook_vnet_uninit(const void *unused __unused) 425a8d61afdSLawrence Stewart { 426a8d61afdSLawrence Stewart struct hhook_head *hhh, *tmphhh; 427a8d61afdSLawrence Stewart 428a8d61afdSLawrence Stewart /* 429a8d61afdSLawrence Stewart * If subsystems which export helper hook points use the hhook KPI 430a8d61afdSLawrence Stewart * correctly, the loop below should have no work to do because the 431a8d61afdSLawrence Stewart * subsystem should have already called hhook_head_deregister(). 432a8d61afdSLawrence Stewart */ 433a8d61afdSLawrence Stewart HHHLIST_LOCK(); 434*601d4c75SLawrence Stewart LIST_FOREACH_SAFE(hhh, &V_hhook_vhead_list, hhh_vnext, tmphhh) { 435a8d61afdSLawrence Stewart printf("%s: hhook_head type=%d, id=%d cleanup required\n", 436a8d61afdSLawrence Stewart __func__, hhh->hhh_type, hhh->hhh_id); 437a8d61afdSLawrence Stewart hhook_head_destroy(hhh); 438a8d61afdSLawrence Stewart } 439a8d61afdSLawrence Stewart HHHLIST_UNLOCK(); 440a8d61afdSLawrence Stewart } 441a8d61afdSLawrence Stewart 442a8d61afdSLawrence Stewart 443a8d61afdSLawrence Stewart /* 444*601d4c75SLawrence Stewart * When a vnet is created and being initialised, init the V_hhook_vhead_list. 445a8d61afdSLawrence Stewart */ 446a8d61afdSLawrence Stewart VNET_SYSINIT(hhook_vnet_init, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, 447a8d61afdSLawrence Stewart hhook_vnet_init, NULL); 448a8d61afdSLawrence Stewart 449a8d61afdSLawrence Stewart /* 450a8d61afdSLawrence Stewart * The hhook KPI provides a mechanism for subsystems which export helper hook 451a8d61afdSLawrence Stewart * points to clean up on vnet tear down, but in case the KPI is misused, 452a8d61afdSLawrence Stewart * provide a function to clean up and free memory for a vnet being destroyed. 453a8d61afdSLawrence Stewart */ 454a8d61afdSLawrence Stewart VNET_SYSUNINIT(hhook_vnet_uninit, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, 455a8d61afdSLawrence Stewart hhook_vnet_uninit, NULL); 456