1a8d61afdSLawrence Stewart /*- 2*b1f53277SLawrence Stewart * Copyright (c) 2010,2013 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/jail.h> 44a8d61afdSLawrence Stewart #include <sys/khelp.h> 45a8d61afdSLawrence Stewart #include <sys/lock.h> 46a8d61afdSLawrence Stewart #include <sys/malloc.h> 47a8d61afdSLawrence Stewart #include <sys/module.h> 48a8d61afdSLawrence Stewart #include <sys/module_khelp.h> 49a8d61afdSLawrence Stewart #include <sys/osd.h> 50a8d61afdSLawrence Stewart #include <sys/queue.h> 51a8d61afdSLawrence Stewart #include <sys/refcount.h> 52a8d61afdSLawrence Stewart #include <sys/rwlock.h> 53a8d61afdSLawrence Stewart #include <sys/systm.h> 54a8d61afdSLawrence Stewart 55a8d61afdSLawrence Stewart #include <net/vnet.h> 56a8d61afdSLawrence Stewart 57a8d61afdSLawrence Stewart static struct rwlock khelp_list_lock; 58a8d61afdSLawrence Stewart RW_SYSINIT(khelplistlock, &khelp_list_lock, "helper list lock"); 59a8d61afdSLawrence Stewart 60a8d61afdSLawrence Stewart static TAILQ_HEAD(helper_head, helper) helpers = TAILQ_HEAD_INITIALIZER(helpers); 61a8d61afdSLawrence Stewart 62a8d61afdSLawrence Stewart /* Private function prototypes. */ 63a8d61afdSLawrence Stewart static inline void khelp_remove_osd(struct helper *h, struct osd *hosd); 64a8d61afdSLawrence Stewart 65a8d61afdSLawrence Stewart #define KHELP_LIST_WLOCK() rw_wlock(&khelp_list_lock) 66a8d61afdSLawrence Stewart #define KHELP_LIST_WUNLOCK() rw_wunlock(&khelp_list_lock) 67a8d61afdSLawrence Stewart #define KHELP_LIST_RLOCK() rw_rlock(&khelp_list_lock) 68a8d61afdSLawrence Stewart #define KHELP_LIST_RUNLOCK() rw_runlock(&khelp_list_lock) 69a8d61afdSLawrence Stewart #define KHELP_LIST_LOCK_ASSERT() rw_assert(&khelp_list_lock, RA_LOCKED) 70a8d61afdSLawrence Stewart 71a8d61afdSLawrence Stewart int 72a8d61afdSLawrence Stewart khelp_register_helper(struct helper *h) 73a8d61afdSLawrence Stewart { 74a8d61afdSLawrence Stewart struct helper *tmph; 75a8d61afdSLawrence Stewart int error, i, inserted; 76a8d61afdSLawrence Stewart 77a8d61afdSLawrence Stewart error = 0; 78a8d61afdSLawrence Stewart inserted = 0; 79a8d61afdSLawrence Stewart refcount_init(&h->h_refcount, 0); 80a8d61afdSLawrence Stewart h->h_id = osd_register(OSD_KHELP, NULL, NULL); 81a8d61afdSLawrence Stewart 82a8d61afdSLawrence Stewart /* It's only safe to add the hooks after osd_register(). */ 83a8d61afdSLawrence Stewart if (h->h_nhooks > 0) { 84a8d61afdSLawrence Stewart for (i = 0; i < h->h_nhooks && !error; i++) { 85a8d61afdSLawrence Stewart /* We don't require the module to assign hook_helper. */ 86a8d61afdSLawrence Stewart h->h_hooks[i].hook_helper = h; 87*b1f53277SLawrence Stewart error = hhook_add_hook_lookup(&h->h_hooks[i], 88*b1f53277SLawrence Stewart HHOOK_WAITOK); 89a8d61afdSLawrence Stewart } 90a8d61afdSLawrence Stewart 91a8d61afdSLawrence Stewart if (error) { 92a8d61afdSLawrence Stewart for (i--; i >= 0; i--) 93*b1f53277SLawrence Stewart hhook_remove_hook_lookup(&h->h_hooks[i]); 94a8d61afdSLawrence Stewart 95a8d61afdSLawrence Stewart osd_deregister(OSD_KHELP, h->h_id); 96a8d61afdSLawrence Stewart } 97a8d61afdSLawrence Stewart } 98a8d61afdSLawrence Stewart 99a8d61afdSLawrence Stewart if (!error) { 100a8d61afdSLawrence Stewart KHELP_LIST_WLOCK(); 101a8d61afdSLawrence Stewart /* 102a8d61afdSLawrence Stewart * Keep list of helpers sorted in descending h_id order. Due to 103a8d61afdSLawrence Stewart * the way osd_set() works, a sorted list ensures 104a8d61afdSLawrence Stewart * init_helper_osd() will operate with improved efficiency. 105a8d61afdSLawrence Stewart */ 106a8d61afdSLawrence Stewart TAILQ_FOREACH(tmph, &helpers, h_next) { 107a8d61afdSLawrence Stewart if (tmph->h_id < h->h_id) { 108a8d61afdSLawrence Stewart TAILQ_INSERT_BEFORE(tmph, h, h_next); 109a8d61afdSLawrence Stewart inserted = 1; 110a8d61afdSLawrence Stewart break; 111a8d61afdSLawrence Stewart } 112a8d61afdSLawrence Stewart } 113a8d61afdSLawrence Stewart 114a8d61afdSLawrence Stewart if (!inserted) 115a8d61afdSLawrence Stewart TAILQ_INSERT_TAIL(&helpers, h, h_next); 116a8d61afdSLawrence Stewart KHELP_LIST_WUNLOCK(); 117a8d61afdSLawrence Stewart } 118a8d61afdSLawrence Stewart 119a8d61afdSLawrence Stewart return (error); 120a8d61afdSLawrence Stewart } 121a8d61afdSLawrence Stewart 122a8d61afdSLawrence Stewart int 123a8d61afdSLawrence Stewart khelp_deregister_helper(struct helper *h) 124a8d61afdSLawrence Stewart { 125a8d61afdSLawrence Stewart struct helper *tmph; 126a8d61afdSLawrence Stewart int error, i; 127a8d61afdSLawrence Stewart 128a8d61afdSLawrence Stewart error = 0; 129a8d61afdSLawrence Stewart 130a8d61afdSLawrence Stewart KHELP_LIST_WLOCK(); 131a8d61afdSLawrence Stewart if (h->h_refcount > 0) 132a8d61afdSLawrence Stewart error = EBUSY; 133a8d61afdSLawrence Stewart else { 134a8d61afdSLawrence Stewart error = ENOENT; 135a8d61afdSLawrence Stewart TAILQ_FOREACH(tmph, &helpers, h_next) { 136a8d61afdSLawrence Stewart if (tmph == h) { 137a8d61afdSLawrence Stewart TAILQ_REMOVE(&helpers, h, h_next); 138a8d61afdSLawrence Stewart error = 0; 139a8d61afdSLawrence Stewart break; 140a8d61afdSLawrence Stewart } 141a8d61afdSLawrence Stewart } 142a8d61afdSLawrence Stewart } 143a8d61afdSLawrence Stewart KHELP_LIST_WUNLOCK(); 144a8d61afdSLawrence Stewart 145a8d61afdSLawrence Stewart if (!error) { 146a8d61afdSLawrence Stewart if (h->h_nhooks > 0) { 147a8d61afdSLawrence Stewart for (i = 0; i < h->h_nhooks; i++) 148*b1f53277SLawrence Stewart hhook_remove_hook_lookup(&h->h_hooks[i]); 149a8d61afdSLawrence Stewart } 150a8d61afdSLawrence Stewart osd_deregister(OSD_KHELP, h->h_id); 151a8d61afdSLawrence Stewart } 152a8d61afdSLawrence Stewart 153a8d61afdSLawrence Stewart return (error); 154a8d61afdSLawrence Stewart } 155a8d61afdSLawrence Stewart 156a8d61afdSLawrence Stewart int 157a8d61afdSLawrence Stewart khelp_init_osd(uint32_t classes, struct osd *hosd) 158a8d61afdSLawrence Stewart { 159a8d61afdSLawrence Stewart struct helper *h; 160a8d61afdSLawrence Stewart void *hdata; 161a8d61afdSLawrence Stewart int error; 162a8d61afdSLawrence Stewart 163a8d61afdSLawrence Stewart KASSERT(hosd != NULL, ("struct osd not initialised!")); 164a8d61afdSLawrence Stewart 165a8d61afdSLawrence Stewart error = 0; 166a8d61afdSLawrence Stewart 167a8d61afdSLawrence Stewart KHELP_LIST_RLOCK(); 168a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) { 169a8d61afdSLawrence Stewart /* If helper is correct class and needs to store OSD... */ 170a8d61afdSLawrence Stewart if (h->h_classes & classes && h->h_flags & HELPER_NEEDS_OSD) { 171a8d61afdSLawrence Stewart hdata = uma_zalloc(h->h_zone, M_NOWAIT); 172a8d61afdSLawrence Stewart if (hdata == NULL) { 173a8d61afdSLawrence Stewart error = ENOMEM; 174a8d61afdSLawrence Stewart break; 175a8d61afdSLawrence Stewart } 176a8d61afdSLawrence Stewart osd_set(OSD_KHELP, hosd, h->h_id, hdata); 177a8d61afdSLawrence Stewart refcount_acquire(&h->h_refcount); 178a8d61afdSLawrence Stewart } 179a8d61afdSLawrence Stewart } 180a8d61afdSLawrence Stewart 181a8d61afdSLawrence Stewart if (error) { 182a8d61afdSLawrence Stewart /* Delete OSD that was assigned prior to the error. */ 183a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) { 184a8d61afdSLawrence Stewart if (h->h_classes & classes) 185a8d61afdSLawrence Stewart khelp_remove_osd(h, hosd); 186a8d61afdSLawrence Stewart } 187a8d61afdSLawrence Stewart } 188a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK(); 189a8d61afdSLawrence Stewart 190a8d61afdSLawrence Stewart return (error); 191a8d61afdSLawrence Stewart } 192a8d61afdSLawrence Stewart 193a8d61afdSLawrence Stewart int 194a8d61afdSLawrence Stewart khelp_destroy_osd(struct osd *hosd) 195a8d61afdSLawrence Stewart { 196a8d61afdSLawrence Stewart struct helper *h; 197a8d61afdSLawrence Stewart int error; 198a8d61afdSLawrence Stewart 199a8d61afdSLawrence Stewart KASSERT(hosd != NULL, ("struct osd not initialised!")); 200a8d61afdSLawrence Stewart 201a8d61afdSLawrence Stewart error = 0; 202a8d61afdSLawrence Stewart 203a8d61afdSLawrence Stewart KHELP_LIST_RLOCK(); 204a8d61afdSLawrence Stewart /* 205a8d61afdSLawrence Stewart * Clean up all khelp related OSD. 206a8d61afdSLawrence Stewart * 207a8d61afdSLawrence Stewart * XXXLAS: Would be nice to use something like osd_exit() here but it 208a8d61afdSLawrence Stewart * doesn't have the right semantics for this purpose. 209a8d61afdSLawrence Stewart */ 210a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) 211a8d61afdSLawrence Stewart khelp_remove_osd(h, hosd); 212a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK(); 213a8d61afdSLawrence Stewart 214a8d61afdSLawrence Stewart return (error); 215a8d61afdSLawrence Stewart } 216a8d61afdSLawrence Stewart 217a8d61afdSLawrence Stewart static inline void 218a8d61afdSLawrence Stewart khelp_remove_osd(struct helper *h, struct osd *hosd) 219a8d61afdSLawrence Stewart { 220a8d61afdSLawrence Stewart void *hdata; 221a8d61afdSLawrence Stewart 222a8d61afdSLawrence Stewart if (h->h_flags & HELPER_NEEDS_OSD) { 223a8d61afdSLawrence Stewart /* 224a8d61afdSLawrence Stewart * If the current helper uses OSD and calling osd_get() 225a8d61afdSLawrence Stewart * on the helper's h_id returns non-NULL, the helper has 226a8d61afdSLawrence Stewart * OSD attached to 'hosd' which needs to be cleaned up. 227a8d61afdSLawrence Stewart */ 228a8d61afdSLawrence Stewart hdata = osd_get(OSD_KHELP, hosd, h->h_id); 229a8d61afdSLawrence Stewart if (hdata != NULL) { 230a8d61afdSLawrence Stewart uma_zfree(h->h_zone, hdata); 231a8d61afdSLawrence Stewart osd_del(OSD_KHELP, hosd, h->h_id); 232a8d61afdSLawrence Stewart refcount_release(&h->h_refcount); 233a8d61afdSLawrence Stewart } 234a8d61afdSLawrence Stewart } 235a8d61afdSLawrence Stewart } 236a8d61afdSLawrence Stewart 237a8d61afdSLawrence Stewart void * 238a8d61afdSLawrence Stewart khelp_get_osd(struct osd *hosd, int32_t id) 239a8d61afdSLawrence Stewart { 240a8d61afdSLawrence Stewart 241a8d61afdSLawrence Stewart return (osd_get(OSD_KHELP, hosd, id)); 242a8d61afdSLawrence Stewart } 243a8d61afdSLawrence Stewart 244a8d61afdSLawrence Stewart int32_t 245a8d61afdSLawrence Stewart khelp_get_id(char *hname) 246a8d61afdSLawrence Stewart { 247a8d61afdSLawrence Stewart struct helper *h; 248a8d61afdSLawrence Stewart int32_t id; 249a8d61afdSLawrence Stewart 250a8d61afdSLawrence Stewart id = -1; 251a8d61afdSLawrence Stewart 252a8d61afdSLawrence Stewart KHELP_LIST_RLOCK(); 253a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) { 254a8d61afdSLawrence Stewart if (strncmp(h->h_name, hname, HELPER_NAME_MAXLEN) == 0) { 255a8d61afdSLawrence Stewart id = h->h_id; 256a8d61afdSLawrence Stewart break; 257a8d61afdSLawrence Stewart } 258a8d61afdSLawrence Stewart } 259a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK(); 260a8d61afdSLawrence Stewart 261a8d61afdSLawrence Stewart return (id); 262a8d61afdSLawrence Stewart } 263a8d61afdSLawrence Stewart 264a8d61afdSLawrence Stewart int 265a8d61afdSLawrence Stewart khelp_add_hhook(struct hookinfo *hki, uint32_t flags) 266a8d61afdSLawrence Stewart { 267a8d61afdSLawrence Stewart int error; 268a8d61afdSLawrence Stewart 269a8d61afdSLawrence Stewart /* 270*b1f53277SLawrence Stewart * XXXLAS: Should probably include the functionality to update the 271*b1f53277SLawrence Stewart * helper's h_hooks struct member. 272a8d61afdSLawrence Stewart */ 273a8d61afdSLawrence Stewart error = hhook_add_hook_lookup(hki, flags); 274a8d61afdSLawrence Stewart 275a8d61afdSLawrence Stewart return (error); 276a8d61afdSLawrence Stewart } 277a8d61afdSLawrence Stewart 278a8d61afdSLawrence Stewart int 279a8d61afdSLawrence Stewart khelp_remove_hhook(struct hookinfo *hki) 280a8d61afdSLawrence Stewart { 281a8d61afdSLawrence Stewart int error; 282a8d61afdSLawrence Stewart 283a8d61afdSLawrence Stewart /* 284*b1f53277SLawrence Stewart * XXXLAS: Should probably include the functionality to update the 285*b1f53277SLawrence Stewart * helper's h_hooks struct member. 286a8d61afdSLawrence Stewart */ 287a8d61afdSLawrence Stewart error = hhook_remove_hook_lookup(hki); 288a8d61afdSLawrence Stewart 289a8d61afdSLawrence Stewart return (error); 290a8d61afdSLawrence Stewart } 291a8d61afdSLawrence Stewart 292a8d61afdSLawrence Stewart int 293a8d61afdSLawrence Stewart khelp_modevent(module_t mod, int event_type, void *data) 294a8d61afdSLawrence Stewart { 295a8d61afdSLawrence Stewart struct khelp_modevent_data *kmd; 296a8d61afdSLawrence Stewart int error; 297a8d61afdSLawrence Stewart 298a8d61afdSLawrence Stewart kmd = (struct khelp_modevent_data *)data; 299a8d61afdSLawrence Stewart error = 0; 300a8d61afdSLawrence Stewart 301a8d61afdSLawrence Stewart switch(event_type) { 302a8d61afdSLawrence Stewart case MOD_LOAD: 303a8d61afdSLawrence Stewart if (kmd->helper->h_flags & HELPER_NEEDS_OSD) { 304a8d61afdSLawrence Stewart if (kmd->uma_zsize <= 0) { 305a8d61afdSLawrence Stewart printf("Use KHELP_DECLARE_MOD_UMA() instead!\n"); 306a8d61afdSLawrence Stewart error = EDOOFUS; 307a8d61afdSLawrence Stewart break; 308a8d61afdSLawrence Stewart } 309a8d61afdSLawrence Stewart kmd->helper->h_zone = uma_zcreate(kmd->name, 310a8d61afdSLawrence Stewart kmd->uma_zsize, kmd->umactor, kmd->umadtor, NULL, 311a8d61afdSLawrence Stewart NULL, 0, 0); 312a8d61afdSLawrence Stewart if (kmd->helper->h_zone == NULL) { 313a8d61afdSLawrence Stewart error = ENOMEM; 314a8d61afdSLawrence Stewart break; 315a8d61afdSLawrence Stewart } 316a8d61afdSLawrence Stewart } 317a8d61afdSLawrence Stewart strlcpy(kmd->helper->h_name, kmd->name, HELPER_NAME_MAXLEN); 318a8d61afdSLawrence Stewart kmd->helper->h_hooks = kmd->hooks; 319a8d61afdSLawrence Stewart kmd->helper->h_nhooks = kmd->nhooks; 320a8d61afdSLawrence Stewart if (kmd->helper->mod_init != NULL) 321a8d61afdSLawrence Stewart error = kmd->helper->mod_init(); 322a8d61afdSLawrence Stewart if (!error) 323a8d61afdSLawrence Stewart error = khelp_register_helper(kmd->helper); 324a8d61afdSLawrence Stewart break; 325a8d61afdSLawrence Stewart 326a8d61afdSLawrence Stewart case MOD_QUIESCE: 327a8d61afdSLawrence Stewart case MOD_SHUTDOWN: 328a8d61afdSLawrence Stewart case MOD_UNLOAD: 329a8d61afdSLawrence Stewart error = khelp_deregister_helper(kmd->helper); 330a8d61afdSLawrence Stewart if (!error) { 331a8d61afdSLawrence Stewart if (kmd->helper->h_flags & HELPER_NEEDS_OSD) 332a8d61afdSLawrence Stewart uma_zdestroy(kmd->helper->h_zone); 333a8d61afdSLawrence Stewart if (kmd->helper->mod_destroy != NULL) 334a8d61afdSLawrence Stewart kmd->helper->mod_destroy(); 335a8d61afdSLawrence Stewart } else if (error == ENOENT) 336a8d61afdSLawrence Stewart /* Do nothing and allow unload if helper not in list. */ 337a8d61afdSLawrence Stewart error = 0; 338a8d61afdSLawrence Stewart else if (error == EBUSY) 339a8d61afdSLawrence Stewart printf("Khelp module \"%s\" can't unload until its " 340a8d61afdSLawrence Stewart "refcount drops from %d to 0.\n", kmd->name, 341a8d61afdSLawrence Stewart kmd->helper->h_refcount); 342a8d61afdSLawrence Stewart break; 343a8d61afdSLawrence Stewart 344a8d61afdSLawrence Stewart default: 345a8d61afdSLawrence Stewart error = EINVAL; 346a8d61afdSLawrence Stewart break; 347a8d61afdSLawrence Stewart } 348a8d61afdSLawrence Stewart 349a8d61afdSLawrence Stewart return (error); 350a8d61afdSLawrence Stewart } 351a8d61afdSLawrence Stewart 352a8d61afdSLawrence Stewart /* 353a8d61afdSLawrence Stewart * This function is called in two separate situations: 354a8d61afdSLawrence Stewart * 355a8d61afdSLawrence Stewart * - When the kernel is booting, it is called directly by the SYSINIT framework 356a8d61afdSLawrence Stewart * to allow Khelp modules which were compiled into the kernel or loaded by the 357a8d61afdSLawrence Stewart * boot loader to insert their non-virtualised hook functions into the kernel. 358a8d61afdSLawrence Stewart * 359a8d61afdSLawrence Stewart * - When the kernel is booting or a vnet is created, this function is also 360a8d61afdSLawrence Stewart * called indirectly through khelp_vnet_init() by the vnet initialisation code. 361a8d61afdSLawrence Stewart * In this situation, Khelp modules are able to insert their virtualised hook 362a8d61afdSLawrence Stewart * functions into the virtualised hook points in the vnet which is being 363a8d61afdSLawrence Stewart * initialised. In the case where the kernel is not compiled with "options 364a8d61afdSLawrence Stewart * VIMAGE", this step is still run once at boot, but the hook functions get 365a8d61afdSLawrence Stewart * transparently inserted into the standard unvirtualised network stack. 366a8d61afdSLawrence Stewart */ 367a8d61afdSLawrence Stewart static void 368a8d61afdSLawrence Stewart khelp_init(const void *vnet) 369a8d61afdSLawrence Stewart { 370a8d61afdSLawrence Stewart struct helper *h; 371a8d61afdSLawrence Stewart int error, i, vinit; 372a8d61afdSLawrence Stewart int32_t htype, hid; 373a8d61afdSLawrence Stewart 374a8d61afdSLawrence Stewart error = 0; 375a8d61afdSLawrence Stewart vinit = vnet != NULL; 376a8d61afdSLawrence Stewart 377a8d61afdSLawrence Stewart KHELP_LIST_RLOCK(); 378a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) { 379a8d61afdSLawrence Stewart for (i = 0; i < h->h_nhooks && !error; i++) { 380a8d61afdSLawrence Stewart htype = h->h_hooks[i].hook_type; 381a8d61afdSLawrence Stewart hid = h->h_hooks[i].hook_id; 382a8d61afdSLawrence Stewart 383a8d61afdSLawrence Stewart /* 384a8d61afdSLawrence Stewart * If we're doing a virtualised init (vinit != 0) and 385a8d61afdSLawrence Stewart * the hook point is virtualised, or we're doing a plain 386a8d61afdSLawrence Stewart * sysinit at boot and the hook point is not 387a8d61afdSLawrence Stewart * virtualised, insert the hook. 388a8d61afdSLawrence Stewart */ 389a8d61afdSLawrence Stewart if ((hhook_head_is_virtualised_lookup(htype, hid) == 390a8d61afdSLawrence Stewart HHOOK_HEADISINVNET && vinit) || 391a8d61afdSLawrence Stewart (!hhook_head_is_virtualised_lookup(htype, hid) && 392a8d61afdSLawrence Stewart !vinit)) { 393a8d61afdSLawrence Stewart error = hhook_add_hook_lookup(&h->h_hooks[i], 394a8d61afdSLawrence Stewart HHOOK_NOWAIT); 395a8d61afdSLawrence Stewart } 396a8d61afdSLawrence Stewart } 397a8d61afdSLawrence Stewart 398a8d61afdSLawrence Stewart if (error) { 399a8d61afdSLawrence Stewart /* Remove any helper's hooks we successfully added. */ 400a8d61afdSLawrence Stewart for (i--; i >= 0; i--) 401a8d61afdSLawrence Stewart hhook_remove_hook_lookup(&h->h_hooks[i]); 402a8d61afdSLawrence Stewart 403a8d61afdSLawrence Stewart printf("%s: Failed to add hooks for helper \"%s\" (%p)", 404a8d61afdSLawrence Stewart __func__, h->h_name, h); 405a8d61afdSLawrence Stewart if (vinit) 406a8d61afdSLawrence Stewart printf(" to vnet %p.\n", vnet); 407a8d61afdSLawrence Stewart else 408a8d61afdSLawrence Stewart printf(".\n"); 409a8d61afdSLawrence Stewart 410a8d61afdSLawrence Stewart error = 0; 411a8d61afdSLawrence Stewart } 412a8d61afdSLawrence Stewart } 413a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK(); 414a8d61afdSLawrence Stewart } 415a8d61afdSLawrence Stewart 416a8d61afdSLawrence Stewart /* 417a8d61afdSLawrence Stewart * Vnet created and being initialised. 418a8d61afdSLawrence Stewart */ 419a8d61afdSLawrence Stewart static void 420a8d61afdSLawrence Stewart khelp_vnet_init(const void *unused __unused) 421a8d61afdSLawrence Stewart { 422a8d61afdSLawrence Stewart 423a8d61afdSLawrence Stewart khelp_init(TD_TO_VNET(curthread)); 424a8d61afdSLawrence Stewart } 425a8d61afdSLawrence Stewart 426a8d61afdSLawrence Stewart 427a8d61afdSLawrence Stewart /* 428a8d61afdSLawrence Stewart * As the kernel boots, allow Khelp modules which were compiled into the kernel 429a8d61afdSLawrence Stewart * or loaded by the boot loader to insert their non-virtualised hook functions 430a8d61afdSLawrence Stewart * into the kernel. 431a8d61afdSLawrence Stewart */ 432a8d61afdSLawrence Stewart SYSINIT(khelp_init, SI_SUB_PROTO_END, SI_ORDER_FIRST, khelp_init, NULL); 433a8d61afdSLawrence Stewart 434a8d61afdSLawrence Stewart /* 435a8d61afdSLawrence Stewart * When a vnet is created and being initialised, we need to insert the helper 436a8d61afdSLawrence Stewart * hook functions for all currently registered Khelp modules into the vnet's 437a8d61afdSLawrence Stewart * helper hook points. The hhook KPI provides a mechanism for subsystems which 438a8d61afdSLawrence Stewart * export helper hook points to clean up on vnet shutdown, so we don't need a 439a8d61afdSLawrence Stewart * VNET_SYSUNINIT for Khelp. 440a8d61afdSLawrence Stewart */ 441a8d61afdSLawrence Stewart VNET_SYSINIT(khelp_vnet_init, SI_SUB_PROTO_END, SI_ORDER_FIRST, 442a8d61afdSLawrence Stewart khelp_vnet_init, NULL); 443