1*a8d61afdSLawrence Stewart /*- 2*a8d61afdSLawrence Stewart * Copyright (c) 2010 Lawrence Stewart <lstewart@freebsd.org> 3*a8d61afdSLawrence Stewart * Copyright (c) 2010 The FreeBSD Foundation 4*a8d61afdSLawrence Stewart * All rights reserved. 5*a8d61afdSLawrence Stewart * 6*a8d61afdSLawrence Stewart * This software was developed by Lawrence Stewart while studying at the Centre 7*a8d61afdSLawrence Stewart * for Advanced Internet Architectures, Swinburne University, made possible in 8*a8d61afdSLawrence Stewart * part by grants from the FreeBSD Foundation and Cisco University Research 9*a8d61afdSLawrence Stewart * Program Fund at Community Foundation Silicon Valley. 10*a8d61afdSLawrence Stewart * 11*a8d61afdSLawrence Stewart * Portions of this software were developed at the Centre for Advanced 12*a8d61afdSLawrence Stewart * Internet Architectures, Swinburne University of Technology, Melbourne, 13*a8d61afdSLawrence Stewart * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. 14*a8d61afdSLawrence Stewart * 15*a8d61afdSLawrence Stewart * Redistribution and use in source and binary forms, with or without 16*a8d61afdSLawrence Stewart * modification, are permitted provided that the following conditions 17*a8d61afdSLawrence Stewart * are met: 18*a8d61afdSLawrence Stewart * 1. Redistributions of source code must retain the above copyright 19*a8d61afdSLawrence Stewart * notice, this list of conditions and the following disclaimer. 20*a8d61afdSLawrence Stewart * 2. Redistributions in binary form must reproduce the above copyright 21*a8d61afdSLawrence Stewart * notice, this list of conditions and the following disclaimer in the 22*a8d61afdSLawrence Stewart * documentation and/or other materials provided with the distribution. 23*a8d61afdSLawrence Stewart * 24*a8d61afdSLawrence Stewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25*a8d61afdSLawrence Stewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26*a8d61afdSLawrence Stewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27*a8d61afdSLawrence Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28*a8d61afdSLawrence Stewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29*a8d61afdSLawrence Stewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30*a8d61afdSLawrence Stewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31*a8d61afdSLawrence Stewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32*a8d61afdSLawrence Stewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33*a8d61afdSLawrence Stewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34*a8d61afdSLawrence Stewart * SUCH DAMAGE. 35*a8d61afdSLawrence Stewart */ 36*a8d61afdSLawrence Stewart 37*a8d61afdSLawrence Stewart #include <sys/cdefs.h> 38*a8d61afdSLawrence Stewart __FBSDID("$FreeBSD$"); 39*a8d61afdSLawrence Stewart 40*a8d61afdSLawrence Stewart #include <sys/param.h> 41*a8d61afdSLawrence Stewart #include <sys/kernel.h> 42*a8d61afdSLawrence Stewart #include <sys/hhook.h> 43*a8d61afdSLawrence Stewart #include <sys/jail.h> 44*a8d61afdSLawrence Stewart #include <sys/khelp.h> 45*a8d61afdSLawrence Stewart #include <sys/lock.h> 46*a8d61afdSLawrence Stewart #include <sys/malloc.h> 47*a8d61afdSLawrence Stewart #include <sys/module.h> 48*a8d61afdSLawrence Stewart #include <sys/module_khelp.h> 49*a8d61afdSLawrence Stewart #include <sys/osd.h> 50*a8d61afdSLawrence Stewart #include <sys/queue.h> 51*a8d61afdSLawrence Stewart #include <sys/refcount.h> 52*a8d61afdSLawrence Stewart #include <sys/rwlock.h> 53*a8d61afdSLawrence Stewart #include <sys/systm.h> 54*a8d61afdSLawrence Stewart 55*a8d61afdSLawrence Stewart #include <net/vnet.h> 56*a8d61afdSLawrence Stewart 57*a8d61afdSLawrence Stewart static struct rwlock khelp_list_lock; 58*a8d61afdSLawrence Stewart RW_SYSINIT(khelplistlock, &khelp_list_lock, "helper list lock"); 59*a8d61afdSLawrence Stewart 60*a8d61afdSLawrence Stewart static TAILQ_HEAD(helper_head, helper) helpers = TAILQ_HEAD_INITIALIZER(helpers); 61*a8d61afdSLawrence Stewart 62*a8d61afdSLawrence Stewart /* Private function prototypes. */ 63*a8d61afdSLawrence Stewart static inline void khelp_remove_osd(struct helper *h, struct osd *hosd); 64*a8d61afdSLawrence Stewart 65*a8d61afdSLawrence Stewart #define KHELP_LIST_WLOCK() rw_wlock(&khelp_list_lock) 66*a8d61afdSLawrence Stewart #define KHELP_LIST_WUNLOCK() rw_wunlock(&khelp_list_lock) 67*a8d61afdSLawrence Stewart #define KHELP_LIST_RLOCK() rw_rlock(&khelp_list_lock) 68*a8d61afdSLawrence Stewart #define KHELP_LIST_RUNLOCK() rw_runlock(&khelp_list_lock) 69*a8d61afdSLawrence Stewart #define KHELP_LIST_LOCK_ASSERT() rw_assert(&khelp_list_lock, RA_LOCKED) 70*a8d61afdSLawrence Stewart 71*a8d61afdSLawrence Stewart int 72*a8d61afdSLawrence Stewart khelp_register_helper(struct helper *h) 73*a8d61afdSLawrence Stewart { 74*a8d61afdSLawrence Stewart struct helper *tmph; 75*a8d61afdSLawrence Stewart int error, i, inserted; 76*a8d61afdSLawrence Stewart 77*a8d61afdSLawrence Stewart error = 0; 78*a8d61afdSLawrence Stewart inserted = 0; 79*a8d61afdSLawrence Stewart refcount_init(&h->h_refcount, 0); 80*a8d61afdSLawrence Stewart h->h_id = osd_register(OSD_KHELP, NULL, NULL); 81*a8d61afdSLawrence Stewart 82*a8d61afdSLawrence Stewart /* It's only safe to add the hooks after osd_register(). */ 83*a8d61afdSLawrence Stewart if (h->h_nhooks > 0) { 84*a8d61afdSLawrence Stewart for (i = 0; i < h->h_nhooks && !error; i++) { 85*a8d61afdSLawrence Stewart /* We don't require the module to assign hook_helper. */ 86*a8d61afdSLawrence Stewart h->h_hooks[i].hook_helper = h; 87*a8d61afdSLawrence Stewart error = khelp_add_hhook(&h->h_hooks[i], HHOOK_NOWAIT); 88*a8d61afdSLawrence Stewart } 89*a8d61afdSLawrence Stewart 90*a8d61afdSLawrence Stewart if (error) { 91*a8d61afdSLawrence Stewart for (i--; i >= 0; i--) 92*a8d61afdSLawrence Stewart khelp_remove_hhook(&h->h_hooks[i]); 93*a8d61afdSLawrence Stewart 94*a8d61afdSLawrence Stewart osd_deregister(OSD_KHELP, h->h_id); 95*a8d61afdSLawrence Stewart } 96*a8d61afdSLawrence Stewart } 97*a8d61afdSLawrence Stewart 98*a8d61afdSLawrence Stewart if (!error) { 99*a8d61afdSLawrence Stewart KHELP_LIST_WLOCK(); 100*a8d61afdSLawrence Stewart /* 101*a8d61afdSLawrence Stewart * Keep list of helpers sorted in descending h_id order. Due to 102*a8d61afdSLawrence Stewart * the way osd_set() works, a sorted list ensures 103*a8d61afdSLawrence Stewart * init_helper_osd() will operate with improved efficiency. 104*a8d61afdSLawrence Stewart */ 105*a8d61afdSLawrence Stewart TAILQ_FOREACH(tmph, &helpers, h_next) { 106*a8d61afdSLawrence Stewart if (tmph->h_id < h->h_id) { 107*a8d61afdSLawrence Stewart TAILQ_INSERT_BEFORE(tmph, h, h_next); 108*a8d61afdSLawrence Stewart inserted = 1; 109*a8d61afdSLawrence Stewart break; 110*a8d61afdSLawrence Stewart } 111*a8d61afdSLawrence Stewart } 112*a8d61afdSLawrence Stewart 113*a8d61afdSLawrence Stewart if (!inserted) 114*a8d61afdSLawrence Stewart TAILQ_INSERT_TAIL(&helpers, h, h_next); 115*a8d61afdSLawrence Stewart KHELP_LIST_WUNLOCK(); 116*a8d61afdSLawrence Stewart } 117*a8d61afdSLawrence Stewart 118*a8d61afdSLawrence Stewart return (error); 119*a8d61afdSLawrence Stewart } 120*a8d61afdSLawrence Stewart 121*a8d61afdSLawrence Stewart int 122*a8d61afdSLawrence Stewart khelp_deregister_helper(struct helper *h) 123*a8d61afdSLawrence Stewart { 124*a8d61afdSLawrence Stewart struct helper *tmph; 125*a8d61afdSLawrence Stewart int error, i; 126*a8d61afdSLawrence Stewart 127*a8d61afdSLawrence Stewart error = 0; 128*a8d61afdSLawrence Stewart 129*a8d61afdSLawrence Stewart KHELP_LIST_WLOCK(); 130*a8d61afdSLawrence Stewart if (h->h_refcount > 0) 131*a8d61afdSLawrence Stewart error = EBUSY; 132*a8d61afdSLawrence Stewart else { 133*a8d61afdSLawrence Stewart error = ENOENT; 134*a8d61afdSLawrence Stewart TAILQ_FOREACH(tmph, &helpers, h_next) { 135*a8d61afdSLawrence Stewart if (tmph == h) { 136*a8d61afdSLawrence Stewart TAILQ_REMOVE(&helpers, h, h_next); 137*a8d61afdSLawrence Stewart error = 0; 138*a8d61afdSLawrence Stewart break; 139*a8d61afdSLawrence Stewart } 140*a8d61afdSLawrence Stewart } 141*a8d61afdSLawrence Stewart } 142*a8d61afdSLawrence Stewart KHELP_LIST_WUNLOCK(); 143*a8d61afdSLawrence Stewart 144*a8d61afdSLawrence Stewart if (!error) { 145*a8d61afdSLawrence Stewart if (h->h_nhooks > 0) { 146*a8d61afdSLawrence Stewart for (i = 0; i < h->h_nhooks; i++) 147*a8d61afdSLawrence Stewart khelp_remove_hhook(&h->h_hooks[i]); 148*a8d61afdSLawrence Stewart } 149*a8d61afdSLawrence Stewart osd_deregister(OSD_KHELP, h->h_id); 150*a8d61afdSLawrence Stewart } 151*a8d61afdSLawrence Stewart 152*a8d61afdSLawrence Stewart return (error); 153*a8d61afdSLawrence Stewart } 154*a8d61afdSLawrence Stewart 155*a8d61afdSLawrence Stewart int 156*a8d61afdSLawrence Stewart khelp_init_osd(uint32_t classes, struct osd *hosd) 157*a8d61afdSLawrence Stewart { 158*a8d61afdSLawrence Stewart struct helper *h; 159*a8d61afdSLawrence Stewart void *hdata; 160*a8d61afdSLawrence Stewart int error; 161*a8d61afdSLawrence Stewart 162*a8d61afdSLawrence Stewart KASSERT(hosd != NULL, ("struct osd not initialised!")); 163*a8d61afdSLawrence Stewart 164*a8d61afdSLawrence Stewart error = 0; 165*a8d61afdSLawrence Stewart 166*a8d61afdSLawrence Stewart KHELP_LIST_RLOCK(); 167*a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) { 168*a8d61afdSLawrence Stewart /* If helper is correct class and needs to store OSD... */ 169*a8d61afdSLawrence Stewart if (h->h_classes & classes && h->h_flags & HELPER_NEEDS_OSD) { 170*a8d61afdSLawrence Stewart hdata = uma_zalloc(h->h_zone, M_NOWAIT); 171*a8d61afdSLawrence Stewart if (hdata == NULL) { 172*a8d61afdSLawrence Stewart error = ENOMEM; 173*a8d61afdSLawrence Stewart break; 174*a8d61afdSLawrence Stewart } 175*a8d61afdSLawrence Stewart osd_set(OSD_KHELP, hosd, h->h_id, hdata); 176*a8d61afdSLawrence Stewart refcount_acquire(&h->h_refcount); 177*a8d61afdSLawrence Stewart } 178*a8d61afdSLawrence Stewart } 179*a8d61afdSLawrence Stewart 180*a8d61afdSLawrence Stewart if (error) { 181*a8d61afdSLawrence Stewart /* Delete OSD that was assigned prior to the error. */ 182*a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) { 183*a8d61afdSLawrence Stewart if (h->h_classes & classes) 184*a8d61afdSLawrence Stewart khelp_remove_osd(h, hosd); 185*a8d61afdSLawrence Stewart } 186*a8d61afdSLawrence Stewart } 187*a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK(); 188*a8d61afdSLawrence Stewart 189*a8d61afdSLawrence Stewart return (error); 190*a8d61afdSLawrence Stewart } 191*a8d61afdSLawrence Stewart 192*a8d61afdSLawrence Stewart int 193*a8d61afdSLawrence Stewart khelp_destroy_osd(struct osd *hosd) 194*a8d61afdSLawrence Stewart { 195*a8d61afdSLawrence Stewart struct helper *h; 196*a8d61afdSLawrence Stewart int error; 197*a8d61afdSLawrence Stewart 198*a8d61afdSLawrence Stewart KASSERT(hosd != NULL, ("struct osd not initialised!")); 199*a8d61afdSLawrence Stewart 200*a8d61afdSLawrence Stewart error = 0; 201*a8d61afdSLawrence Stewart 202*a8d61afdSLawrence Stewart KHELP_LIST_RLOCK(); 203*a8d61afdSLawrence Stewart /* 204*a8d61afdSLawrence Stewart * Clean up all khelp related OSD. 205*a8d61afdSLawrence Stewart * 206*a8d61afdSLawrence Stewart * XXXLAS: Would be nice to use something like osd_exit() here but it 207*a8d61afdSLawrence Stewart * doesn't have the right semantics for this purpose. 208*a8d61afdSLawrence Stewart */ 209*a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) 210*a8d61afdSLawrence Stewart khelp_remove_osd(h, hosd); 211*a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK(); 212*a8d61afdSLawrence Stewart 213*a8d61afdSLawrence Stewart return (error); 214*a8d61afdSLawrence Stewart } 215*a8d61afdSLawrence Stewart 216*a8d61afdSLawrence Stewart static inline void 217*a8d61afdSLawrence Stewart khelp_remove_osd(struct helper *h, struct osd *hosd) 218*a8d61afdSLawrence Stewart { 219*a8d61afdSLawrence Stewart void *hdata; 220*a8d61afdSLawrence Stewart 221*a8d61afdSLawrence Stewart if (h->h_flags & HELPER_NEEDS_OSD) { 222*a8d61afdSLawrence Stewart /* 223*a8d61afdSLawrence Stewart * If the current helper uses OSD and calling osd_get() 224*a8d61afdSLawrence Stewart * on the helper's h_id returns non-NULL, the helper has 225*a8d61afdSLawrence Stewart * OSD attached to 'hosd' which needs to be cleaned up. 226*a8d61afdSLawrence Stewart */ 227*a8d61afdSLawrence Stewart hdata = osd_get(OSD_KHELP, hosd, h->h_id); 228*a8d61afdSLawrence Stewart if (hdata != NULL) { 229*a8d61afdSLawrence Stewart uma_zfree(h->h_zone, hdata); 230*a8d61afdSLawrence Stewart osd_del(OSD_KHELP, hosd, h->h_id); 231*a8d61afdSLawrence Stewart refcount_release(&h->h_refcount); 232*a8d61afdSLawrence Stewart } 233*a8d61afdSLawrence Stewart } 234*a8d61afdSLawrence Stewart } 235*a8d61afdSLawrence Stewart 236*a8d61afdSLawrence Stewart void * 237*a8d61afdSLawrence Stewart khelp_get_osd(struct osd *hosd, int32_t id) 238*a8d61afdSLawrence Stewart { 239*a8d61afdSLawrence Stewart 240*a8d61afdSLawrence Stewart return (osd_get(OSD_KHELP, hosd, id)); 241*a8d61afdSLawrence Stewart } 242*a8d61afdSLawrence Stewart 243*a8d61afdSLawrence Stewart int32_t 244*a8d61afdSLawrence Stewart khelp_get_id(char *hname) 245*a8d61afdSLawrence Stewart { 246*a8d61afdSLawrence Stewart struct helper *h; 247*a8d61afdSLawrence Stewart int32_t id; 248*a8d61afdSLawrence Stewart 249*a8d61afdSLawrence Stewart id = -1; 250*a8d61afdSLawrence Stewart 251*a8d61afdSLawrence Stewart KHELP_LIST_RLOCK(); 252*a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) { 253*a8d61afdSLawrence Stewart if (strncmp(h->h_name, hname, HELPER_NAME_MAXLEN) == 0) { 254*a8d61afdSLawrence Stewart id = h->h_id; 255*a8d61afdSLawrence Stewart break; 256*a8d61afdSLawrence Stewart } 257*a8d61afdSLawrence Stewart } 258*a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK(); 259*a8d61afdSLawrence Stewart 260*a8d61afdSLawrence Stewart return (id); 261*a8d61afdSLawrence Stewart } 262*a8d61afdSLawrence Stewart 263*a8d61afdSLawrence Stewart int 264*a8d61afdSLawrence Stewart khelp_add_hhook(struct hookinfo *hki, uint32_t flags) 265*a8d61afdSLawrence Stewart { 266*a8d61afdSLawrence Stewart VNET_ITERATOR_DECL(vnet_iter); 267*a8d61afdSLawrence Stewart int error; 268*a8d61afdSLawrence Stewart 269*a8d61afdSLawrence Stewart error = 0; 270*a8d61afdSLawrence Stewart 271*a8d61afdSLawrence Stewart /* 272*a8d61afdSLawrence Stewart * XXXLAS: If a helper is dynamically adding a helper hook function at 273*a8d61afdSLawrence Stewart * runtime using this function, we should update the helper's h_hooks 274*a8d61afdSLawrence Stewart * struct member to include the additional hookinfo struct. 275*a8d61afdSLawrence Stewart */ 276*a8d61afdSLawrence Stewart 277*a8d61afdSLawrence Stewart VNET_LIST_RLOCK_NOSLEEP(); 278*a8d61afdSLawrence Stewart VNET_FOREACH(vnet_iter) { 279*a8d61afdSLawrence Stewart CURVNET_SET(vnet_iter); 280*a8d61afdSLawrence Stewart error = hhook_add_hook_lookup(hki, flags); 281*a8d61afdSLawrence Stewart CURVNET_RESTORE(); 282*a8d61afdSLawrence Stewart #ifdef VIMAGE 283*a8d61afdSLawrence Stewart if (error) 284*a8d61afdSLawrence Stewart break; 285*a8d61afdSLawrence Stewart #endif 286*a8d61afdSLawrence Stewart } 287*a8d61afdSLawrence Stewart VNET_LIST_RUNLOCK_NOSLEEP(); 288*a8d61afdSLawrence Stewart 289*a8d61afdSLawrence Stewart return (error); 290*a8d61afdSLawrence Stewart } 291*a8d61afdSLawrence Stewart 292*a8d61afdSLawrence Stewart int 293*a8d61afdSLawrence Stewart khelp_remove_hhook(struct hookinfo *hki) 294*a8d61afdSLawrence Stewart { 295*a8d61afdSLawrence Stewart VNET_ITERATOR_DECL(vnet_iter); 296*a8d61afdSLawrence Stewart int error; 297*a8d61afdSLawrence Stewart 298*a8d61afdSLawrence Stewart error = 0; 299*a8d61afdSLawrence Stewart 300*a8d61afdSLawrence Stewart /* 301*a8d61afdSLawrence Stewart * XXXLAS: If a helper is dynamically removing a helper hook function at 302*a8d61afdSLawrence Stewart * runtime using this function, we should update the helper's h_hooks 303*a8d61afdSLawrence Stewart * struct member to remove the defunct hookinfo struct. 304*a8d61afdSLawrence Stewart */ 305*a8d61afdSLawrence Stewart 306*a8d61afdSLawrence Stewart VNET_LIST_RLOCK_NOSLEEP(); 307*a8d61afdSLawrence Stewart VNET_FOREACH(vnet_iter) { 308*a8d61afdSLawrence Stewart CURVNET_SET(vnet_iter); 309*a8d61afdSLawrence Stewart error = hhook_remove_hook_lookup(hki); 310*a8d61afdSLawrence Stewart CURVNET_RESTORE(); 311*a8d61afdSLawrence Stewart #ifdef VIMAGE 312*a8d61afdSLawrence Stewart if (error) 313*a8d61afdSLawrence Stewart break; 314*a8d61afdSLawrence Stewart #endif 315*a8d61afdSLawrence Stewart } 316*a8d61afdSLawrence Stewart VNET_LIST_RUNLOCK_NOSLEEP(); 317*a8d61afdSLawrence Stewart 318*a8d61afdSLawrence Stewart return (error); 319*a8d61afdSLawrence Stewart } 320*a8d61afdSLawrence Stewart 321*a8d61afdSLawrence Stewart int 322*a8d61afdSLawrence Stewart khelp_modevent(module_t mod, int event_type, void *data) 323*a8d61afdSLawrence Stewart { 324*a8d61afdSLawrence Stewart struct khelp_modevent_data *kmd; 325*a8d61afdSLawrence Stewart int error; 326*a8d61afdSLawrence Stewart 327*a8d61afdSLawrence Stewart kmd = (struct khelp_modevent_data *)data; 328*a8d61afdSLawrence Stewart error = 0; 329*a8d61afdSLawrence Stewart 330*a8d61afdSLawrence Stewart switch(event_type) { 331*a8d61afdSLawrence Stewart case MOD_LOAD: 332*a8d61afdSLawrence Stewart if (kmd->helper->h_flags & HELPER_NEEDS_OSD) { 333*a8d61afdSLawrence Stewart if (kmd->uma_zsize <= 0) { 334*a8d61afdSLawrence Stewart printf("Use KHELP_DECLARE_MOD_UMA() instead!\n"); 335*a8d61afdSLawrence Stewart error = EDOOFUS; 336*a8d61afdSLawrence Stewart break; 337*a8d61afdSLawrence Stewart } 338*a8d61afdSLawrence Stewart kmd->helper->h_zone = uma_zcreate(kmd->name, 339*a8d61afdSLawrence Stewart kmd->uma_zsize, kmd->umactor, kmd->umadtor, NULL, 340*a8d61afdSLawrence Stewart NULL, 0, 0); 341*a8d61afdSLawrence Stewart if (kmd->helper->h_zone == NULL) { 342*a8d61afdSLawrence Stewart error = ENOMEM; 343*a8d61afdSLawrence Stewart break; 344*a8d61afdSLawrence Stewart } 345*a8d61afdSLawrence Stewart } 346*a8d61afdSLawrence Stewart strlcpy(kmd->helper->h_name, kmd->name, HELPER_NAME_MAXLEN); 347*a8d61afdSLawrence Stewart kmd->helper->h_hooks = kmd->hooks; 348*a8d61afdSLawrence Stewart kmd->helper->h_nhooks = kmd->nhooks; 349*a8d61afdSLawrence Stewart if (kmd->helper->mod_init != NULL) 350*a8d61afdSLawrence Stewart error = kmd->helper->mod_init(); 351*a8d61afdSLawrence Stewart if (!error) 352*a8d61afdSLawrence Stewart error = khelp_register_helper(kmd->helper); 353*a8d61afdSLawrence Stewart break; 354*a8d61afdSLawrence Stewart 355*a8d61afdSLawrence Stewart case MOD_QUIESCE: 356*a8d61afdSLawrence Stewart case MOD_SHUTDOWN: 357*a8d61afdSLawrence Stewart case MOD_UNLOAD: 358*a8d61afdSLawrence Stewart error = khelp_deregister_helper(kmd->helper); 359*a8d61afdSLawrence Stewart if (!error) { 360*a8d61afdSLawrence Stewart if (kmd->helper->h_flags & HELPER_NEEDS_OSD) 361*a8d61afdSLawrence Stewart uma_zdestroy(kmd->helper->h_zone); 362*a8d61afdSLawrence Stewart if (kmd->helper->mod_destroy != NULL) 363*a8d61afdSLawrence Stewart kmd->helper->mod_destroy(); 364*a8d61afdSLawrence Stewart } else if (error == ENOENT) 365*a8d61afdSLawrence Stewart /* Do nothing and allow unload if helper not in list. */ 366*a8d61afdSLawrence Stewart error = 0; 367*a8d61afdSLawrence Stewart else if (error == EBUSY) 368*a8d61afdSLawrence Stewart printf("Khelp module \"%s\" can't unload until its " 369*a8d61afdSLawrence Stewart "refcount drops from %d to 0.\n", kmd->name, 370*a8d61afdSLawrence Stewart kmd->helper->h_refcount); 371*a8d61afdSLawrence Stewart break; 372*a8d61afdSLawrence Stewart 373*a8d61afdSLawrence Stewart default: 374*a8d61afdSLawrence Stewart error = EINVAL; 375*a8d61afdSLawrence Stewart break; 376*a8d61afdSLawrence Stewart } 377*a8d61afdSLawrence Stewart 378*a8d61afdSLawrence Stewart return (error); 379*a8d61afdSLawrence Stewart } 380*a8d61afdSLawrence Stewart 381*a8d61afdSLawrence Stewart /* 382*a8d61afdSLawrence Stewart * This function is called in two separate situations: 383*a8d61afdSLawrence Stewart * 384*a8d61afdSLawrence Stewart * - When the kernel is booting, it is called directly by the SYSINIT framework 385*a8d61afdSLawrence Stewart * to allow Khelp modules which were compiled into the kernel or loaded by the 386*a8d61afdSLawrence Stewart * boot loader to insert their non-virtualised hook functions into the kernel. 387*a8d61afdSLawrence Stewart * 388*a8d61afdSLawrence Stewart * - When the kernel is booting or a vnet is created, this function is also 389*a8d61afdSLawrence Stewart * called indirectly through khelp_vnet_init() by the vnet initialisation code. 390*a8d61afdSLawrence Stewart * In this situation, Khelp modules are able to insert their virtualised hook 391*a8d61afdSLawrence Stewart * functions into the virtualised hook points in the vnet which is being 392*a8d61afdSLawrence Stewart * initialised. In the case where the kernel is not compiled with "options 393*a8d61afdSLawrence Stewart * VIMAGE", this step is still run once at boot, but the hook functions get 394*a8d61afdSLawrence Stewart * transparently inserted into the standard unvirtualised network stack. 395*a8d61afdSLawrence Stewart */ 396*a8d61afdSLawrence Stewart static void 397*a8d61afdSLawrence Stewart khelp_init(const void *vnet) 398*a8d61afdSLawrence Stewart { 399*a8d61afdSLawrence Stewart struct helper *h; 400*a8d61afdSLawrence Stewart int error, i, vinit; 401*a8d61afdSLawrence Stewart int32_t htype, hid; 402*a8d61afdSLawrence Stewart 403*a8d61afdSLawrence Stewart error = 0; 404*a8d61afdSLawrence Stewart vinit = vnet != NULL; 405*a8d61afdSLawrence Stewart 406*a8d61afdSLawrence Stewart KHELP_LIST_RLOCK(); 407*a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) { 408*a8d61afdSLawrence Stewart for (i = 0; i < h->h_nhooks && !error; i++) { 409*a8d61afdSLawrence Stewart htype = h->h_hooks[i].hook_type; 410*a8d61afdSLawrence Stewart hid = h->h_hooks[i].hook_id; 411*a8d61afdSLawrence Stewart 412*a8d61afdSLawrence Stewart /* 413*a8d61afdSLawrence Stewart * If we're doing a virtualised init (vinit != 0) and 414*a8d61afdSLawrence Stewart * the hook point is virtualised, or we're doing a plain 415*a8d61afdSLawrence Stewart * sysinit at boot and the hook point is not 416*a8d61afdSLawrence Stewart * virtualised, insert the hook. 417*a8d61afdSLawrence Stewart */ 418*a8d61afdSLawrence Stewart if ((hhook_head_is_virtualised_lookup(htype, hid) == 419*a8d61afdSLawrence Stewart HHOOK_HEADISINVNET && vinit) || 420*a8d61afdSLawrence Stewart (!hhook_head_is_virtualised_lookup(htype, hid) && 421*a8d61afdSLawrence Stewart !vinit)) { 422*a8d61afdSLawrence Stewart error = hhook_add_hook_lookup(&h->h_hooks[i], 423*a8d61afdSLawrence Stewart HHOOK_NOWAIT); 424*a8d61afdSLawrence Stewart } 425*a8d61afdSLawrence Stewart } 426*a8d61afdSLawrence Stewart 427*a8d61afdSLawrence Stewart if (error) { 428*a8d61afdSLawrence Stewart /* Remove any helper's hooks we successfully added. */ 429*a8d61afdSLawrence Stewart for (i--; i >= 0; i--) 430*a8d61afdSLawrence Stewart hhook_remove_hook_lookup(&h->h_hooks[i]); 431*a8d61afdSLawrence Stewart 432*a8d61afdSLawrence Stewart printf("%s: Failed to add hooks for helper \"%s\" (%p)", 433*a8d61afdSLawrence Stewart __func__, h->h_name, h); 434*a8d61afdSLawrence Stewart if (vinit) 435*a8d61afdSLawrence Stewart printf(" to vnet %p.\n", vnet); 436*a8d61afdSLawrence Stewart else 437*a8d61afdSLawrence Stewart printf(".\n"); 438*a8d61afdSLawrence Stewart 439*a8d61afdSLawrence Stewart error = 0; 440*a8d61afdSLawrence Stewart } 441*a8d61afdSLawrence Stewart } 442*a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK(); 443*a8d61afdSLawrence Stewart } 444*a8d61afdSLawrence Stewart 445*a8d61afdSLawrence Stewart /* 446*a8d61afdSLawrence Stewart * Vnet created and being initialised. 447*a8d61afdSLawrence Stewart */ 448*a8d61afdSLawrence Stewart static void 449*a8d61afdSLawrence Stewart khelp_vnet_init(const void *unused __unused) 450*a8d61afdSLawrence Stewart { 451*a8d61afdSLawrence Stewart 452*a8d61afdSLawrence Stewart khelp_init(TD_TO_VNET(curthread)); 453*a8d61afdSLawrence Stewart } 454*a8d61afdSLawrence Stewart 455*a8d61afdSLawrence Stewart 456*a8d61afdSLawrence Stewart /* 457*a8d61afdSLawrence Stewart * As the kernel boots, allow Khelp modules which were compiled into the kernel 458*a8d61afdSLawrence Stewart * or loaded by the boot loader to insert their non-virtualised hook functions 459*a8d61afdSLawrence Stewart * into the kernel. 460*a8d61afdSLawrence Stewart */ 461*a8d61afdSLawrence Stewart SYSINIT(khelp_init, SI_SUB_PROTO_END, SI_ORDER_FIRST, khelp_init, NULL); 462*a8d61afdSLawrence Stewart 463*a8d61afdSLawrence Stewart /* 464*a8d61afdSLawrence Stewart * When a vnet is created and being initialised, we need to insert the helper 465*a8d61afdSLawrence Stewart * hook functions for all currently registered Khelp modules into the vnet's 466*a8d61afdSLawrence Stewart * helper hook points. The hhook KPI provides a mechanism for subsystems which 467*a8d61afdSLawrence Stewart * export helper hook points to clean up on vnet shutdown, so we don't need a 468*a8d61afdSLawrence Stewart * VNET_SYSUNINIT for Khelp. 469*a8d61afdSLawrence Stewart */ 470*a8d61afdSLawrence Stewart VNET_SYSINIT(khelp_vnet_init, SI_SUB_PROTO_END, SI_ORDER_FIRST, 471*a8d61afdSLawrence Stewart khelp_vnet_init, NULL); 472