diff options
author | dh155122 <none@none> | 2007-01-19 16:59:38 -0800 |
---|---|---|
committer | dh155122 <none@none> | 2007-01-19 16:59:38 -0800 |
commit | f4b3ec61df05330d25f55a36b975b4d7519fdeb1 (patch) | |
tree | 395c234b901886c84a82603a767e031fca136e09 /usr/src/uts/common/io/hook.c | |
parent | 2e59fc6dac28cd69376c21d6b90a5624160ba94c (diff) | |
download | illumos-joyent-f4b3ec61df05330d25f55a36b975b4d7519fdeb1.tar.gz |
PSARC 2006/366 IP Instances
6289221 RFE: Need virtualized ip-stack for each local zone
6512601 panic in ipsec_in_tag - allocation failure
6514637 error message from dhcpagent: add_pkt_opt: option type 60 is missing required value
6364643 RFE: allow persistent setting of interface flags per zone
6307539 RFE: Invalid network address causes zone boot failure
5041214 Allow IPMP configuration with zones
5005887 RFE: zoneadmd should support plumbing an interface via DHCP
4991139 RFE: zones should provide a mechanism to configure a defaultrouter for a zone
6218378 zoneadmd doesn't set the netmask for non-loopback addresses hosted on lo0
4963280 zones: need to virtualize the IPv6 default address selection mechanism
4963285 zones: need support of stateless address autoconfiguration for IPv6
5048068 zones don't boot if one of its interfaces has failed
5057154 RFE: ability to change interface status from within a zone
4963287 zones should support the plumbing of the first (and only) logical interface
4978517 TCP privileged port space should be partitioned per zone
5023347 zones don't work well with network routes other than default
4963372 investigate whether global zone can act as a router for local zones
6378364 RFE: Allow each zone to have its own virtual IPFilter
Diffstat (limited to 'usr/src/uts/common/io/hook.c')
-rw-r--r-- | usr/src/uts/common/io/hook.c | 172 |
1 files changed, 125 insertions, 47 deletions
diff --git a/usr/src/uts/common/io/hook.c b/usr/src/uts/common/io/hook.c index 7e791647e4..323503498c 100644 --- a/usr/src/uts/common/io/hook.c +++ b/usr/src/uts/common/io/hook.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -54,19 +54,20 @@ static struct modlinkage modlinkage = { * Hook internal functions */ static hook_int_t *hook_copy(hook_t *src); -static hook_event_int_t *hook_event_checkdup(hook_event_t *he); +static hook_event_int_t *hook_event_checkdup(hook_event_t *he, + hook_stack_t *hks); static hook_event_int_t *hook_event_copy(hook_event_t *src); static hook_event_int_t *hook_event_find(hook_family_int_t *hfi, char *event); static void hook_event_free(hook_event_int_t *hei); static hook_family_int_t *hook_family_copy(hook_family_t *src); -static hook_family_int_t *hook_family_find(char *family); +static hook_family_int_t *hook_family_find(char *family, hook_stack_t *hks); static void hook_family_free(hook_family_int_t *hfi); static hook_int_t *hook_find(hook_event_int_t *hei, hook_t *h); static void hook_free(hook_int_t *hi); static void hook_init(void); - -static cvwaitlock_t familylock; /* global lock */ -static hook_family_int_head_t familylist; /* family list head */ +static void hook_fini(void); +static void *hook_stack_init(netstackid_t stackid, netstack_t *ns); +static void hook_stack_fini(netstackid_t stackid, void *arg); /* * Module entry points. @@ -74,15 +75,27 @@ static hook_family_int_head_t familylist; /* family list head */ int _init(void) { + int error; + hook_init(); - return (mod_install(&modlinkage)); + error = mod_install(&modlinkage); + if (error != 0) + hook_fini(); + + return (error); } int _fini(void) { - return (mod_remove(&modlinkage)); + int error; + + error = mod_remove(&modlinkage); + if (error == 0) + hook_fini(); + + return (error); } @@ -103,10 +116,63 @@ _info(struct modinfo *modinfop) static void hook_init(void) { - CVW_INIT(&familylock); - SLIST_INIT(&familylist); + /* + * We want to be informed each time a stack is created or + * destroyed in the kernel. + */ + netstack_register(NS_HOOK, hook_stack_init, NULL, + hook_stack_fini); +} + +/* + * Function: hook_fini + * Returns: None + * Parameters: None + * + * Deinitialize hooks + */ +static void +hook_fini(void) +{ + netstack_unregister(NS_HOOK); } +/* + * Initialize the hook stack instance. + */ +/*ARGSUSED*/ +static void * +hook_stack_init(netstackid_t stackid, netstack_t *ns) +{ + hook_stack_t *hks; + +#ifdef NS_DEBUG + printf("hook_stack_init(stack %d)\n", stackid); +#endif + + hks = (hook_stack_t *)kmem_zalloc(sizeof (*hks), KM_SLEEP); + hks->hk_netstack = ns; + + CVW_INIT(&hks->hks_familylock); + SLIST_INIT(&hks->hks_familylist); + + return (hks); +} + +/* + * Free the hook stack instance. + */ +/*ARGSUSED*/ +static void +hook_stack_fini(netstackid_t stackid, void *arg) +{ + hook_stack_t *hks = (hook_stack_t *)arg; +#ifdef NS_DEBUG + printf("hook_stack_fini(%p, stack %d)\n", arg, stackid); +#endif + CVW_DESTROY(&hks->hks_familylock); + kmem_free(hks, sizeof (*hks)); +} /* * Function: hook_run @@ -121,10 +187,11 @@ hook_init(void) * called more than once, simultaneously. */ int -hook_run(hook_event_token_t token, hook_data_t info) +hook_run(hook_event_token_t token, hook_data_t info, netstack_t *ns) { hook_int_t *hi; hook_event_int_t *hei; + hook_stack_t *hks = ns->netstack_hook; int rval = 0; ASSERT(token != NULL); @@ -135,7 +202,7 @@ hook_run(hook_event_token_t token, hook_data_t info) hook_data_t, info); /* Hold global read lock to ensure event will not be deleted */ - CVW_ENTER_READ(&familylock); + CVW_ENTER_READ(&hks->hks_familylock); /* Hold event read lock to ensure hook will not be changed */ CVW_ENTER_READ(&hei->hei_lock); @@ -146,7 +213,7 @@ hook_run(hook_event_token_t token, hook_data_t info) hook_event_token_t, token, hook_data_t, info, hook_int_t *, hi); - rval = (*hi->hi_hook.h_func)(token, info); + rval = (*hi->hi_hook.h_func)(token, info, ns); DTRACE_PROBE4(hook__func__end, hook_event_token_t, token, hook_data_t, info, @@ -157,7 +224,7 @@ hook_run(hook_event_token_t token, hook_data_t info) } CVW_EXIT_READ(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); DTRACE_PROBE3(hook__run__end, hook_event_token_t, token, @@ -176,7 +243,7 @@ hook_run(hook_event_token_t token, hook_data_t info) * Add new family to family list */ hook_family_int_t * -hook_family_add(hook_family_t *hf) +hook_family_add(hook_family_t *hf, hook_stack_t *hks) { hook_family_int_t *hfi, *new; @@ -187,20 +254,22 @@ hook_family_add(hook_family_t *hf) if (new == NULL) return (NULL); - CVW_ENTER_WRITE(&familylock); + CVW_ENTER_WRITE(&hks->hks_familylock); /* search family list */ - hfi = hook_family_find(hf->hf_name); + hfi = hook_family_find(hf->hf_name, hks); if (hfi != NULL) { - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); hook_family_free(new); return (NULL); } + new->hfi_ptr = (void *)hks; + /* Add to family list head */ - SLIST_INSERT_HEAD(&familylist, new, hfi_entry); + SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry); - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); return (new); } @@ -215,21 +284,23 @@ hook_family_add(hook_family_t *hf) int hook_family_remove(hook_family_int_t *hfi) { + hook_stack_t *hks; ASSERT(hfi != NULL); + hks = (hook_stack_t *)hfi->hfi_ptr; - CVW_ENTER_WRITE(&familylock); + CVW_ENTER_WRITE(&hks->hks_familylock); /* Check if there are events */ if (!SLIST_EMPTY(&hfi->hfi_head)) { - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); return (EBUSY); } /* Remove from family list */ - SLIST_REMOVE(&familylist, hfi, hook_family_int, hfi_entry); + SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int, hfi_entry); - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); hook_family_free(hfi); return (0); @@ -269,7 +340,6 @@ hook_family_copy(hook_family_t *src) /* - * Function: hook_family_find * Returns: internal family pointer - NULL = Not match * Parameters: family(I) - family name string * @@ -277,13 +347,13 @@ hook_family_copy(hook_family_t *src) * A lock on familylock must be held when called. */ static hook_family_int_t * -hook_family_find(char *family) +hook_family_find(char *family, hook_stack_t *hks) { hook_family_int_t *hfi = NULL; ASSERT(family != NULL); - SLIST_FOREACH(hfi, &familylist, hfi_entry) { + SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { if (strcmp(hfi->hfi_family.hf_name, family) == 0) break; } @@ -328,22 +398,24 @@ hook_family_free(hook_family_int_t *hfi) hook_event_int_t * hook_event_add(hook_family_int_t *hfi, hook_event_t *he) { + hook_stack_t *hks; hook_event_int_t *hei, *new; ASSERT(hfi != NULL); ASSERT(he != NULL); ASSERT(he->he_name != NULL); + hks = (hook_stack_t *)hfi->hfi_ptr; new = hook_event_copy(he); if (new == NULL) return (NULL); - CVW_ENTER_WRITE(&familylock); + CVW_ENTER_WRITE(&hks->hks_familylock); /* Check whether this event pointer is already registered */ - hei = hook_event_checkdup(he); + hei = hook_event_checkdup(he, hks); if (hei != NULL) { - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); hook_event_free(new); return (NULL); } @@ -351,7 +423,7 @@ hook_event_add(hook_family_int_t *hfi, hook_event_t *he) /* Add to event list head */ SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry); - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); return (new); } @@ -367,29 +439,31 @@ hook_event_add(hook_family_int_t *hfi, hook_event_t *he) int hook_event_remove(hook_family_int_t *hfi, hook_event_t *he) { + hook_stack_t *hks; hook_event_int_t *hei; ASSERT(hfi != NULL); ASSERT(he != NULL); + hks = (hook_stack_t *)hfi->hfi_ptr; - CVW_ENTER_WRITE(&familylock); + CVW_ENTER_WRITE(&hks->hks_familylock); hei = hook_event_find(hfi, he->he_name); if (hei == NULL) { - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); return (ENXIO); } /* Check if there are registered hooks for this event */ if (!TAILQ_EMPTY(&hei->hei_head)) { - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); return (EBUSY); } /* Remove from event list */ SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry); - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); hook_event_free(hei); return (0); @@ -405,14 +479,14 @@ hook_event_remove(hook_family_int_t *hfi, hook_event_t *he) * A lock on familylock must be held when called. */ static hook_event_int_t * -hook_event_checkdup(hook_event_t *he) +hook_event_checkdup(hook_event_t *he, hook_stack_t *hks) { hook_family_int_t *hfi; hook_event_int_t *hei; ASSERT(he != NULL); - SLIST_FOREACH(hfi, &familylist, hfi_entry) { + SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { if (hei->hei_event == he) return (hei); @@ -456,7 +530,7 @@ hook_event_copy(hook_event_t *src) * event(I) - event name string * * Search event list with event name - * A lock on familylock must be held when called. + * A lock on hks->hks_familylock must be held when called. */ static hook_event_int_t * hook_event_find(hook_family_int_t *hfi, char *event) @@ -503,12 +577,14 @@ hook_event_free(hook_event_int_t *hei) int hook_register(hook_family_int_t *hfi, char *event, hook_t *h) { + hook_stack_t *hks; hook_event_int_t *hei; hook_int_t *hi, *new; ASSERT(hfi != NULL); ASSERT(event != NULL); ASSERT(h != NULL); + hks = (hook_stack_t *)hfi->hfi_ptr; /* Alloc hook_int_t and copy hook */ new = hook_copy(h); @@ -520,11 +596,11 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h) * to hold global family write lock. Just get read lock here to * ensure event will not be removed when doing hooks operation */ - CVW_ENTER_READ(&familylock); + CVW_ENTER_READ(&hks->hks_familylock); hei = hook_event_find(hfi, event); if (hei == NULL) { - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); hook_free(new); return (ENXIO); } @@ -535,7 +611,7 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h) if (((hei->hei_event->he_flags & HOOK_RDONLY) == 0) && (!TAILQ_EMPTY(&hei->hei_head))) { CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); hook_free(new); return (EEXIST); } @@ -543,7 +619,7 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h) hi = hook_find(hei, h); if (hi != NULL) { CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); hook_free(new); return (EEXIST); } @@ -553,7 +629,7 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h) hei->hei_event->he_interested = B_TRUE; CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); return (0); } @@ -570,17 +646,19 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h) int hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) { + hook_stack_t *hks; hook_event_int_t *hei; hook_int_t *hi; ASSERT(hfi != NULL); ASSERT(h != NULL); + hks = (hook_stack_t *)hfi->hfi_ptr; - CVW_ENTER_READ(&familylock); + CVW_ENTER_READ(&hks->hks_familylock); hei = hook_event_find(hfi, event); if (hei == NULL) { - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); return (ENXIO); } @@ -590,7 +668,7 @@ hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) hi = hook_find(hei, h); if (hi == NULL) { CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); return (ENXIO); } @@ -601,7 +679,7 @@ hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) } CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); hook_free(hi); return (0); |