diff options
author | Darren Reed <Darren.Reed@Sun.COM> | 2008-09-08 14:46:50 -0700 |
---|---|---|
committer | Darren Reed <Darren.Reed@Sun.COM> | 2008-09-08 14:46:50 -0700 |
commit | 7ddc9b1afd18f260b9fb78ec7732facd91769131 (patch) | |
tree | 1a305ae7471e9362c1ba0ea3d32834448059eb00 /usr/src | |
parent | 7739299d04f7910358ca2ad79106f174022a9ab2 (diff) | |
download | illumos-gate-7ddc9b1afd18f260b9fb78ec7732facd91769131.tar.gz |
PSARC/2008/219 Committed API for packet interception
PSARC/2008/335 Corrections for Committed API for packet interception
PSARC/2008/557 Revision to net instance notification API
4844507 Solaris needs stable interface for packet filtering software
6705155 ipf_stack_init() assumes kmem_alloc with KM_NOSLEEP never fails
Diffstat (limited to 'usr/src')
44 files changed, 4195 insertions, 1534 deletions
diff --git a/usr/src/cmd/ipf/tools/ip_fil.c b/usr/src/cmd/ipf/tools/ip_fil.c index 29d69a8b07..a9824140d8 100644 --- a/usr/src/cmd/ipf/tools/ip_fil.c +++ b/usr/src/cmd/ipf/tools/ip_fil.c @@ -7,8 +7,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.133.2.9 2005/01/08 14:22:18 darrenr Exp $"; @@ -175,9 +173,8 @@ static int write_output __P((struct ifnet *, struct mbuf *, #endif -int iplattach(ifs, ns) +int iplattach(ifs) ipf_stack_t *ifs; -netstack_t *ns; { ifs->ifs_fr_running = 1; return 0; @@ -311,7 +308,7 @@ int mode; if (error) break; if (tmp) - error = iplattach(ifs, NULL); + error = iplattach(ifs); else error = ipldetach(ifs); } diff --git a/usr/src/cmd/ipf/tools/ipftest.c b/usr/src/cmd/ipf/tools/ipftest.c index 4463e132de..04e1322acf 100644 --- a/usr/src/cmd/ipf/tools/ipftest.c +++ b/usr/src/cmd/ipf/tools/ipftest.c @@ -3,12 +3,10 @@ * * See the IPFILTER.LICENCE file for details on licencing. * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "ipf.h" #include "ipt.h" #include <sys/ioctl.h> @@ -40,7 +38,6 @@ void drain_log __P((char *, ipf_stack_t *ifs)); void fixv4sums __P((mb_t *, ip_t *)); ipf_stack_t *get_ifs __P((void)); ipf_stack_t *create_ifs __P((void)); -netstack_t *create_ns __P((void)); #if defined(__NetBSD__) || defined(__OpenBSD__) || SOLARIS || \ @@ -84,7 +81,6 @@ char *argv[]; mb_t mb, *m; ip_t *ip; ipf_stack_t *ifs; - netstack_t *ns; m = &mb; dir = 0; @@ -99,8 +95,6 @@ char *argv[]; initparse(); ifs = create_ifs(); - ns = create_ns(); - ifs->ifs_netstack = ns; #if defined(IPFILTER_DEFAULT_BLOCK) ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; @@ -829,13 +823,3 @@ get_ifs() { return (gifs); } - -netstack_t * -create_ns() -{ - netstack_t *ns; - - KMALLOCS(ns, netstack_t *, sizeof (*ns)); - bzero(ns, sizeof (*ns)); - return (ns); -} diff --git a/usr/src/cmd/mdb/common/modules/hook/hook.c b/usr/src/cmd/mdb/common/modules/hook/hook.c index ec9679b2f9..353a592c64 100644 --- a/usr/src/cmd/mdb/common/modules/hook/hook.c +++ b/usr/src/cmd/mdb/common/modules/hook/hook.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/rwlock.h> #include <mdb/mdb_modapi.h> @@ -47,6 +45,8 @@ hooklist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) char hrstr[MAX_LENGTH]; GElf_Sym sym; char buf[MDB_SYM_NAMLEN + 1]; + char *hintname; + hook_t *h; if (argc) return (DCMD_USAGE); @@ -56,8 +56,9 @@ hooklist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) return (DCMD_ERR); } - mdb_printf("%<u>%?s %10s %20s %?s%</u>\n", - "ADDR", "FLAG", "FUNC", "NAME"); + mdb_printf("%<u>%?s %8s %20s %4s %24s %24s%</u>\n", + "ADDR", "FLAG", "FUNC", "HINT", "NAME", "HINTVALUE"); + h = &hl.hi_hook; hlp = TAILQ_FIRST(&hr.hei_head); while (hlp) { if (mdb_vread((void *)&hl, sizeof (hl), @@ -66,30 +67,39 @@ hooklist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) hlp); return (DCMD_ERR); } - if (!hl.hi_hook.h_name) { - mdb_warn("hook list at %p has null role", - hl.hi_hook); + if (!h->h_name) { + mdb_warn("hook list at %p has null role", h); return (DCMD_ERR); } if (mdb_readstr((char *)hrstr, sizeof (hrstr), - (uintptr_t)hl.hi_hook.h_name) == -1) { - mdb_warn("couldn't read list role at %p", - hl.hi_hook.h_name); + (uintptr_t)h->h_name) == -1) { + mdb_warn("couldn't read list role at %p", h->h_name); return (DCMD_ERR); } - if (mdb_lookup_by_addr((uintptr_t)hl.hi_hook.h_func, + switch (h->h_hint) { + case HH_BEFORE : + case HH_AFTER : + hintname = h->h_hintvalue ? + (char *)h->h_hintvalue : ""; + break; + default : + hintname = ""; + break; + } + if (mdb_lookup_by_addr((uintptr_t)h->h_func, MDB_SYM_EXACT, buf, sizeof (buf), &sym) == -1) - mdb_printf("%0?p %10x %0?p %10s\n", - hlp, hl.hi_hook.h_flags, hl.hi_hook.h_func, hrstr); + mdb_printf("%0?p %8x %0?p %4d %24s %24s\n", + hlp, h->h_flags, h->h_func, + h->h_hint, hrstr, hintname); else - mdb_printf("%0?p %10x %20s %10s\n", - hlp, hl.hi_hook.h_flags, buf, hrstr); + mdb_printf("%0?p %8x %20s %4d %24s %24s\n", + hlp, h->h_flags, buf, + h->h_hint, hrstr, hintname); hlp = TAILQ_NEXT(&hl, hi_entry); } return (DCMD_OK); } - /* * List pfhooks event information. * List the hooks information in verbose mode as well. @@ -217,7 +227,7 @@ hookevent_stack_walk_init(mdb_walk_state_t *wsp) } wsp->walk_addr = (uintptr_t)SLIST_FIRST(&hf.hfi_head); return (wsp->walk_callback(wsp->walk_addr, wsp->walk_data, - wsp->walk_cbdata)); + wsp->walk_cbdata)); } static int @@ -234,7 +244,7 @@ hookevent_stack_walk_step(mdb_walk_state_t *wsp) if (wsp->walk_addr == NULL) return (WALK_DONE); return (wsp->walk_callback(wsp->walk_addr, wsp->walk_data, - wsp->walk_cbdata)); + wsp->walk_cbdata)); } static const mdb_dcmd_t dcmds[] = { diff --git a/usr/src/cmd/mdb/common/modules/neti/neti.c b/usr/src/cmd/mdb/common/modules/neti/neti.c index e58fa42f0b..e18110997f 100644 --- a/usr/src/cmd/mdb/common/modules/neti/neti.c +++ b/usr/src/cmd/mdb/common/modules/neti/neti.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/rwlock.h> #include <mdb/mdb_modapi.h> @@ -72,15 +70,15 @@ netinfolist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_warn("couldn't read netinfo at %p", p); return (DCMD_ERR); } - if (!nd.netd_info.neti_protocol) { + if (!nd.netd_info.netp_name) { mdb_warn("netinfo at %p has null protocol", - nd.netd_info.neti_protocol); + nd.netd_info.netp_name); return (DCMD_ERR); } if (mdb_readstr((char *)str, sizeof (str), - (uintptr_t)nd.netd_info.neti_protocol) == -1) { + (uintptr_t)nd.netd_info.netp_name) == -1) { mdb_warn("couldn't read protocol at %p", - nd.netd_info.neti_protocol); + nd.netd_info.netp_name); return (DCMD_ERR); } diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 89132ff644..b1b98171a9 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -495,7 +495,7 @@ IP6_OBJS += ip6ddi.o HOOK_OBJS += hook.o -NETI_OBJS += neti.o +NETI_OBJS += neti_impl.o neti_mod.o neti_stack.o KEYSOCK_OBJS += keysockddi.o keysock.o keysock_opt_data.o diff --git a/usr/src/uts/common/inet/arp/arp.c b/usr/src/uts/common/inet/arp/arp.c index 7ad9f29d25..314963616d 100644 --- a/usr/src/uts/common/inet/arp/arp.c +++ b/usr/src/uts/common/inet/arp/arp.c @@ -229,6 +229,7 @@ static mblk_t *ar_cmd_dequeue(arl_t *arl); static void *arp_stack_init(netstackid_t stackid, netstack_t *ns); static void arp_stack_fini(netstackid_t stackid, void *arg); +static void arp_stack_shutdown(netstackid_t stackid, void *arg); /* * All of these are alterable, within the min/max values given, * at run time. arp_publish_interval and arp_publish_count are @@ -1042,8 +1043,8 @@ ar_close(queue_t *q) info.hne_event = NE_UNPLUMB; info.hne_data = name; info.hne_datalen = strlen(name); - (void) hook_run(as->as_arpnicevents, (hook_data_t)&info, - as->as_netstack); + (void) hook_run(as->as_net_data->netd_hooks, + as->as_arpnicevents, (hook_data_t)&info); } netstack_rele(as->as_netstack); return (0); @@ -3730,8 +3731,8 @@ ar_slifname(queue_t *q, mblk_t *mp_orig) info.hne_event = NE_PLUMB; info.hne_data = arl->arl_name; info.hne_datalen = strlen(arl->arl_name); - (void) hook_run(as->as_arpnicevents, (hook_data_t)&info, - as->as_netstack); + (void) hook_run(as->as_net_data->netd_hooks, as->as_arpnicevents, + (hook_data_t)&info); /* Chain in the new arl. */ rw_enter(&as->as_arl_lock, RW_WRITER); @@ -4473,7 +4474,8 @@ arp_ddi_init(void) * destroyed in the kernel, so we can maintain the * set of arp_stack_t's. */ - netstack_register(NS_ARP, arp_stack_init, NULL, arp_stack_fini); + netstack_register(NS_ARP, arp_stack_init, arp_stack_shutdown, + arp_stack_fini); } void @@ -4506,12 +4508,22 @@ arp_stack_init(netstackid_t stackid, netstack_t *ns) as->as_arp_counter_wrapped = 0; rw_init(&as->as_arl_lock, NULL, RW_DRIVER, NULL); - arp_net_init(as, ns); + arp_net_init(as, stackid); arp_hook_init(as); return (as); } +/* ARGSUSED */ +static void +arp_stack_shutdown(netstackid_t stackid, void *arg) +{ + arp_stack_t *as = (arp_stack_t *)arg; + + arp_hook_destroy(as); + arp_net_destroy(as); +} + /* * Free the ARP stack instance. */ @@ -4521,10 +4533,7 @@ arp_stack_fini(netstackid_t stackid, void *arg) { arp_stack_t *as = (arp_stack_t *)arg; - arp_hook_destroy(as); - arp_net_destroy(as); rw_destroy(&as->as_arl_lock); - nd_free(&as->as_nd); kmem_free(as->as_param_arr, sizeof (arp_param_arr)); as->as_param_arr = NULL; diff --git a/usr/src/uts/common/inet/arp/arp_netinfo.c b/usr/src/uts/common/inet/arp/arp_netinfo.c index e45475f3bf..56ac894408 100644 --- a/usr/src/uts/common/inet/arp/arp_netinfo.c +++ b/usr/src/uts/common/inet/arp/arp_netinfo.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/param.h> #include <sys/types.h> #include <sys/systm.h> @@ -43,20 +41,20 @@ /* * ARP netinfo entry point declarations. */ -static int arp_getifname(phy_if_t, char *, const size_t, netstack_t *); -static int arp_getmtu(phy_if_t, lif_if_t, netstack_t *); -static int arp_getpmtuenabled(netstack_t *); -static int arp_getlifaddr(phy_if_t, lif_if_t, size_t, - net_ifaddr_t [], void *, netstack_t *); -static phy_if_t arp_phygetnext(phy_if_t, netstack_t *); -static phy_if_t arp_phylookup(const char *, netstack_t *); -static lif_if_t arp_lifgetnext(phy_if_t, lif_if_t, netstack_t *); -static int arp_inject(inject_t, net_inject_t *, netstack_t *); -static phy_if_t arp_routeto(struct sockaddr *, netstack_t *); -static int arp_ispartialchecksum(mblk_t *); -static int arp_isvalidchecksum(mblk_t *); - -static net_info_t arp_netinfo = { +static int arp_getifname(net_handle_t, phy_if_t, char *, const size_t); +static int arp_getmtu(net_handle_t, phy_if_t, lif_if_t); +static int arp_getpmtuenabled(net_handle_t); +static int arp_getlifaddr(net_handle_t, phy_if_t, lif_if_t, size_t, + net_ifaddr_t [], void *); +static phy_if_t arp_phygetnext(net_handle_t, phy_if_t); +static phy_if_t arp_phylookup(net_handle_t, const char *); +static lif_if_t arp_lifgetnext(net_handle_t, phy_if_t, lif_if_t); +static int arp_inject(net_handle_t, inject_t, net_inject_t *); +static phy_if_t arp_routeto(net_handle_t, struct sockaddr *, struct sockaddr *); +static int arp_ispartialchecksum(net_handle_t, mblk_t *); +static int arp_isvalidchecksum(net_handle_t, mblk_t *); + +static net_protocol_t arp_netinfo = { NETINFO_VERSION, NHF_ARP, arp_getifname, @@ -76,9 +74,14 @@ static net_info_t arp_netinfo = { * Register ARP netinfo functions. */ void -arp_net_init(arp_stack_t *as, netstack_t *ns) +arp_net_init(arp_stack_t *as, netstackid_t stackid) { - as->as_net_data = net_register_impl(&arp_netinfo, ns); + netid_t id; + + id = net_getnetidbynetstackid(stackid); + ASSERT(id != -1); + + as->as_net_data = net_protocol_register(id, &arp_netinfo); ASSERT(as->as_net_data != NULL); } @@ -88,7 +91,7 @@ arp_net_init(arp_stack_t *as, netstack_t *ns) void arp_net_destroy(arp_stack_t *as) { - (void) net_unregister(as->as_net_data); + (void) net_protocol_unregister(as->as_net_data); } /* @@ -98,33 +101,33 @@ void arp_hook_init(arp_stack_t *as) { HOOK_FAMILY_INIT(&as->as_arproot, Hn_ARP); - if (net_register_family(as->as_net_data, &as->as_arproot) != 0) { + if (net_family_register(as->as_net_data, &as->as_arproot) != 0) { cmn_err(CE_NOTE, "arp_hook_init: " - "net_register_family failed for arp"); + "net_family_register failed for arp"); } HOOK_EVENT_INIT(&as->as_arp_physical_in_event, NH_PHYSICAL_IN); - as->as_arp_physical_in = net_register_event(as->as_net_data, + as->as_arp_physical_in = net_event_register(as->as_net_data, &as->as_arp_physical_in_event); if (as->as_arp_physical_in == NULL) { cmn_err(CE_NOTE, "arp_hook_init: " - "net_register_event failed for arp/physical_in"); + "net_event_register failed for arp/physical_in"); } HOOK_EVENT_INIT(&as->as_arp_physical_out_event, NH_PHYSICAL_OUT); - as->as_arp_physical_out = net_register_event(as->as_net_data, + as->as_arp_physical_out = net_event_register(as->as_net_data, &as->as_arp_physical_out_event); if (as->as_arp_physical_out == NULL) { cmn_err(CE_NOTE, "arp_hook_init: " - "net_register_event failed for arp/physical_out"); + "net_event_register failed for arp/physical_out"); } HOOK_EVENT_INIT(&as->as_arp_nic_events, NH_NIC_EVENTS); - as->as_arpnicevents = net_register_event(as->as_net_data, + as->as_arpnicevents = net_event_register(as->as_net_data, &as->as_arp_nic_events); if (as->as_arpnicevents == NULL) { cmn_err(CE_NOTE, "arp_hook_init: " - "net_register_event failed for arp/nic_events"); + "net_event_register failed for arp/nic_events"); } } @@ -132,35 +135,36 @@ void arp_hook_destroy(arp_stack_t *as) { if (as->as_arpnicevents != NULL) { - if (net_unregister_event(as->as_net_data, + if (net_event_unregister(as->as_net_data, &as->as_arp_nic_events) == 0) as->as_arpnicevents = NULL; } if (as->as_arp_physical_out != NULL) { - if (net_unregister_event(as->as_net_data, + if (net_event_unregister(as->as_net_data, &as->as_arp_physical_out_event) == 0) as->as_arp_physical_out = NULL; } if (as->as_arp_physical_in != NULL) { - if (net_unregister_event(as->as_net_data, + if (net_event_unregister(as->as_net_data, &as->as_arp_physical_in_event) == 0) as->as_arp_physical_in = NULL; } - (void) net_unregister_family(as->as_net_data, &as->as_arproot); + (void) net_family_unregister(as->as_net_data, &as->as_arproot); } /* * Determine the name of the lower level interface */ static int -arp_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen, - netstack_t *ns) +arp_getifname(net_handle_t net, phy_if_t phy_ifdata, char *buffer, + const size_t buflen) { arl_t *arl; arp_stack_t *as; + netstack_t *ns = net->netd_stack->nts_netstack; ASSERT(buffer != NULL); ASSERT(ns != NULL); @@ -184,7 +188,7 @@ arp_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen, */ /*ARGSUSED*/ static int -arp_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) +arp_getmtu(net_handle_t net, phy_if_t phy_ifdata, lif_if_t ifdata) { return (-1); } @@ -194,7 +198,7 @@ arp_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) */ /*ARGSUSED*/ static int -arp_getpmtuenabled(netstack_t *ns) +arp_getpmtuenabled(net_handle_t net) { return (-1); } @@ -204,8 +208,8 @@ arp_getpmtuenabled(netstack_t *ns) */ /*ARGSUSED*/ static int -arp_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem, - net_ifaddr_t type[], void *storage, netstack_t *ns) +arp_getlifaddr(net_handle_t net, phy_if_t phy_ifdata, lif_if_t ifdata, + size_t nelem, net_ifaddr_t type[], void *storage) { return (-1); } @@ -214,11 +218,12 @@ arp_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem, * Determine the instance number of the next lower level interface */ static phy_if_t -arp_phygetnext(phy_if_t phy_ifdata, netstack_t *ns) +arp_phygetnext(net_handle_t net, phy_if_t phy_ifdata) { arl_t *arl; int index; arp_stack_t *as; + netstack_t *ns = net->netd_stack->nts_netstack; ASSERT(ns != NULL); @@ -247,11 +252,12 @@ arp_phygetnext(phy_if_t phy_ifdata, netstack_t *ns) * Given a network interface name, find its ARP layer instance number. */ static phy_if_t -arp_phylookup(const char *name, netstack_t *ns) +arp_phylookup(net_handle_t net, const char *name) { arl_t *arl; int index; arp_stack_t *as; + netstack_t *ns = net->netd_stack->nts_netstack; ASSERT(name != NULL); ASSERT(ns != NULL); @@ -276,7 +282,7 @@ arp_phylookup(const char *name, netstack_t *ns) */ /*ARGSUSED*/ static lif_if_t -arp_lifgetnext(phy_if_t ifp, lif_if_t lif, netstack_t *ns) +arp_lifgetnext(net_handle_t net, phy_if_t ifp, lif_if_t lif) { return ((lif_if_t)-1); } @@ -286,7 +292,7 @@ arp_lifgetnext(phy_if_t ifp, lif_if_t lif, netstack_t *ns) */ /*ARGSUSED*/ static int -arp_inject(inject_t injection, net_inject_t *neti, netstack_t *ns) +arp_inject(net_handle_t net, inject_t injection, net_inject_t *neti) { return (-1); } @@ -296,7 +302,7 @@ arp_inject(inject_t injection, net_inject_t *neti, netstack_t *ns) */ /*ARGSUSED*/ static phy_if_t -arp_routeto(struct sockaddr *addr, netstack_t *ns) +arp_routeto(net_handle_t net, struct sockaddr *addr, struct sockaddr *next) { return ((phy_if_t)-1); } @@ -306,7 +312,7 @@ arp_routeto(struct sockaddr *addr, netstack_t *ns) */ /*ARGSUSED*/ int -arp_ispartialchecksum(mblk_t *mb) +arp_ispartialchecksum(net_handle_t net, mblk_t *mb) { return (-1); } @@ -316,7 +322,7 @@ arp_ispartialchecksum(mblk_t *mb) */ /*ARGSUSED*/ static int -arp_isvalidchecksum(mblk_t *mb) +arp_isvalidchecksum(net_handle_t net, mblk_t *mb) { return (-1); } diff --git a/usr/src/uts/common/inet/arp_impl.h b/usr/src/uts/common/inet/arp_impl.h index a9be780a42..8f59d7a56f 100644 --- a/usr/src/uts/common/inet/arp_impl.h +++ b/usr/src/uts/common/inet/arp_impl.h @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ARP_IMPL_H #define _ARP_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -124,13 +122,14 @@ typedef struct ace_s { if ((_hook).he_interested) { \ hook_pkt_event_t info; \ \ + info.hpe_protocol = as->as_net_data; \ info.hpe_ifp = _ilp; \ info.hpe_ofp = 0; \ info.hpe_hdr = _hdr; \ info.hpe_mp = &(_fm); \ info.hpe_mb = _m; \ - if (hook_run(_event, (hook_data_t)&info, \ - as->as_netstack) != 0) { \ + if (hook_run(as->as_net_data->netd_hooks, \ + _event, (hook_data_t)&info) != 0) { \ if (_fm != NULL) { \ freemsg(_fm); \ _fm = NULL; \ @@ -148,13 +147,14 @@ typedef struct ace_s { if ((_hook).he_interested) { \ hook_pkt_event_t info; \ \ + info.hpe_protocol = as->as_net_data; \ info.hpe_ifp = 0; \ info.hpe_ofp = _olp; \ info.hpe_hdr = _hdr; \ info.hpe_mp = &(_fm); \ info.hpe_mb = _m; \ - if (hook_run(_event, (hook_data_t)&info, \ - as->as_netstack) != 0) { \ + if (hook_run(as->as_net_data->netd_hooks, \ + _event, (hook_data_t)&info) != 0) { \ if (_fm != NULL) { \ freemsg(_fm); \ _fm = NULL; \ @@ -211,7 +211,7 @@ struct arp_stack { hook_event_token_t as_arp_physical_out; hook_event_token_t as_arpnicevents; - net_data_t as_net_data; + net_handle_t as_net_data; }; typedef struct arp_stack arp_stack_t; @@ -236,7 +236,7 @@ typedef struct ar_s { extern void arp_hook_init(arp_stack_t *); extern void arp_hook_destroy(arp_stack_t *); -extern void arp_net_init(arp_stack_t *, netstack_t *); +extern void arp_net_init(arp_stack_t *, netstackid_t); extern void arp_net_destroy(arp_stack_t *); #endif /* _KERNEL */ diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index 21416d0d0b..7dd21ae1b3 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -28,8 +28,6 @@ #ifndef _INET_IP_H #define _INET_IP_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -1894,7 +1892,7 @@ typedef struct ill_s { /* * NIC event information attached, to be used by nic event hooks. */ - hook_nic_event_t *ill_nic_event_info; + hook_nic_event_int_t *ill_nic_event_info; /* Used for IP frag reassembly throttling on a per ILL basis. */ uint_t ill_ipf_gen; /* Generation of next fragment queue */ @@ -2989,12 +2987,13 @@ extern struct module_info ip_mod_info; (_olp))->ill_phyint->phyint_hook_ifindex; \ else \ info.hpe_ofp = 0; \ + info.hpe_protocol = ipst->ips_ipv4_net_data; \ info.hpe_hdr = _iph; \ info.hpe_mp = &(_fm); \ info.hpe_mb = _m; \ info.hpe_flags = _llm; \ - if (hook_run(_event, (hook_data_t)&info, \ - ipst->ips_netstack) != 0) { \ + if (hook_run(ipst->ips_ipv4_net_data->netd_hooks, \ + _event, (hook_data_t)&info) != 0) { \ ip2dbg(("%s hook dropped mblk chain %p hdr %p\n",\ (_hook).he_name, (void *)_fm, (void *)_m)); \ if (_fm != NULL) { \ @@ -3032,12 +3031,13 @@ extern struct module_info ip_mod_info; (_olp))->ill_phyint->phyint_hook_ifindex; \ else \ info.hpe_ofp = 0; \ + info.hpe_protocol = ipst->ips_ipv6_net_data; \ info.hpe_hdr = _iph; \ info.hpe_mp = &(_fm); \ info.hpe_mb = _m; \ info.hpe_flags = _llm; \ - if (hook_run(_event, (hook_data_t)&info, \ - ipst->ips_netstack) != 0) { \ + if (hook_run(ipst->ips_ipv6_net_data->netd_hooks, \ + _event, (hook_data_t)&info) != 0) { \ ip2dbg(("%s hook dropped mblk chain %p hdr %p\n",\ (_hook).he_name, (void *)_fm, (void *)_m)); \ if (_fm != NULL) { \ diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c index cc890ddbe2..42adc33a54 100644 --- a/usr/src/uts/common/inet/ip/ip.c +++ b/usr/src/uts/common/inet/ip/ip.c @@ -5710,6 +5710,18 @@ ip_stack_shutdown(netstackid_t stackid, void *arg) /* Get rid of loopback interfaces and their IREs */ ip_loopback_cleanup(ipst); + + /* + * The destroy functions here will end up causing notify callbacks + * in the hook framework and these need to be run before the shtudown + * of the hook framework is begun - that happens from netstack after + * IP shutdown has completed. If we leave doing these actions until + * ip_stack_fini then the notify callbacks for the net_*_unregister + * are happening against a backdrop of shattered terain. + */ + ipv4_hook_destroy(ipst); + ipv6_hook_destroy(ipst); + ip_net_destroy(ipst); } /* @@ -5724,10 +5736,6 @@ ip_stack_fini(netstackid_t stackid, void *arg) #ifdef NS_DEBUG printf("ip_stack_fini(%p, stack %d)\n", (void *)ipst, stackid); #endif - ipv4_hook_destroy(ipst); - ipv6_hook_destroy(ipst); - ip_net_destroy(ipst); - rw_destroy(&ipst->ips_srcid_lock); ip_kstat_fini(stackid, ipst->ips_ip_mibkp); diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c index 8407012da1..1f94033f84 100644 --- a/usr/src/uts/common/inet/ip/ip_if.c +++ b/usr/src/uts/common/inet/ip/ip_if.c @@ -4309,7 +4309,7 @@ ill_delete_interface_type(ill_if_t *interface) static void ill_glist_delete(ill_t *ill) { - hook_nic_event_t *info; + hook_nic_event_int_t *info; ip_stack_t *ipst; if (ill == NULL) @@ -4353,7 +4353,7 @@ ill_glist_delete(ill_t *ill) * order of them in the kernel. */ info = ill->ill_nic_event_info; - if (info != NULL && info->hne_event == NE_DOWN) { + if (info != NULL && info->hnei_event.hne_event == NE_DOWN) { mutex_enter(&ill->ill_lock); ill_nic_info_dispatch(ill); mutex_exit(&ill->ill_lock); @@ -22748,7 +22748,7 @@ ill_nic_info_plumb(ill_t *ill, boolean_t group) void ill_nic_info_dispatch(ill_t *ill) { - hook_nic_event_t *info; + hook_nic_event_int_t *info; ASSERT(MUTEX_HELD(&ill->ill_lock)); @@ -22757,9 +22757,11 @@ ill_nic_info_dispatch(ill_t *ill) ip_ne_queue_func, info, DDI_SLEEP) == DDI_FAILURE) { ip2dbg(("ill_nic_info_dispatch: " "ddi_taskq_dispatch failed\n")); - if (info->hne_data != NULL) - kmem_free(info->hne_data, info->hne_datalen); - kmem_free(info, sizeof (hook_nic_event_t)); + if (info->hnei_event.hne_data != NULL) { + kmem_free(info->hnei_event.hne_data, + info->hnei_event.hne_datalen); + } + kmem_free(info, sizeof (*info)); } ill->ill_nic_event_info = NULL; } @@ -24384,12 +24386,14 @@ ill_hook_event2str(nic_event_t event) static void ill_hook_event_destroy(ill_t *ill) { - hook_nic_event_t *info; + hook_nic_event_int_t *info; if ((info = ill->ill_nic_event_info) != NULL) { - if (info->hne_data != NULL) - kmem_free(info->hne_data, info->hne_datalen); - kmem_free(info, sizeof (hook_nic_event_t)); + if (info->hnei_event.hne_data != NULL) { + kmem_free(info->hnei_event.hne_data, + info->hnei_event.hne_datalen); + } + kmem_free(info, sizeof (*info)); ill->ill_nic_event_info = NULL; } @@ -24401,39 +24405,41 @@ ill_hook_event_create(ill_t *ill, lif_if_t lif, nic_event_t event, nic_event_data_t data, size_t datalen) { ip_stack_t *ipst = ill->ill_ipst; - hook_nic_event_t *info; + hook_nic_event_int_t *info; const char *str = NULL; /* destroy nic event info if it exists */ if ((info = ill->ill_nic_event_info) != NULL) { - str = ill_hook_event2str(info->hne_event); + str = ill_hook_event2str(info->hnei_event.hne_event); ip2dbg(("ill_hook_event_create: unexpected nic event %s " "attached for %s\n", str, ill->ill_name)); ill_hook_event_destroy(ill); } /* create a new nic event info */ - if ((info = kmem_alloc(sizeof (hook_nic_event_t), KM_NOSLEEP)) == NULL) + info = kmem_alloc(sizeof (*info), KM_NOSLEEP); + if (info == NULL) goto fail; ill->ill_nic_event_info = info; if (event == NE_UNPLUMB) - info->hne_nic = ill->ill_phyint->phyint_ifindex; + info->hnei_event.hne_nic = ill->ill_phyint->phyint_ifindex; else - info->hne_nic = ill->ill_phyint->phyint_hook_ifindex; - info->hne_lif = lif; - info->hne_event = event; - info->hne_family = ill->ill_isv6 ? + info->hnei_event.hne_nic = ill->ill_phyint->phyint_hook_ifindex; + info->hnei_event.hne_lif = lif; + info->hnei_event.hne_event = event; + info->hnei_event.hne_protocol = ill->ill_isv6 ? ipst->ips_ipv6_net_data : ipst->ips_ipv4_net_data; - info->hne_data = NULL; - info->hne_datalen = 0; + info->hnei_event.hne_data = NULL; + info->hnei_event.hne_datalen = 0; + info->hnei_stackid = ipst->ips_netstack->netstack_stackid; if (data != NULL && datalen != 0) { - info->hne_data = kmem_alloc(datalen, KM_NOSLEEP); - if (info->hne_data != NULL) { - bcopy(data, info->hne_data, datalen); - info->hne_datalen = datalen; + info->hnei_event.hne_data = kmem_alloc(datalen, KM_NOSLEEP); + if (info->hnei_event.hne_data != NULL) { + bcopy(data, info->hnei_event.hne_data, datalen); + info->hnei_event.hne_datalen = datalen; } else { ill_hook_event_destroy(ill); goto fail; diff --git a/usr/src/uts/common/inet/ip/ip_netinfo.c b/usr/src/uts/common/inet/ip/ip_netinfo.c index 9c073e795c..aea6870d12 100644 --- a/usr/src/uts/common/inet/ip/ip_netinfo.c +++ b/usr/src/uts/common/inet/ip/ip_netinfo.c @@ -23,8 +23,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/param.h> #include <sys/types.h> #include <sys/systm.h> @@ -37,6 +35,7 @@ #include <sys/socket.h> #include <sys/neti.h> #include <sys/sdt.h> +#include <sys/cmn_err.h> #include <netinet/in.h> #include <inet/common.h> @@ -54,46 +53,49 @@ /* * IPv4 netinfo entry point declarations. */ -static int ip_getifname(phy_if_t, char *, const size_t, - netstack_t *); -static int ip_getmtu(phy_if_t, lif_if_t, netstack_t *); -static int ip_getpmtuenabled(netstack_t *); -static int ip_getlifaddr(phy_if_t, lif_if_t, size_t, - net_ifaddr_t [], void *, netstack_t *); -static phy_if_t ip_phygetnext(phy_if_t, netstack_t *); -static phy_if_t ip_phylookup(const char *, netstack_t *); -static lif_if_t ip_lifgetnext(phy_if_t, lif_if_t, netstack_t *); -static int ip_inject(inject_t, net_inject_t *, netstack_t *); -static phy_if_t ip_routeto(struct sockaddr *, netstack_t *); -static int ip_ispartialchecksum(mblk_t *); -static int ip_isvalidchecksum(mblk_t *); - -static int ipv6_getifname(phy_if_t, char *, const size_t, - netstack_t *); -static int ipv6_getmtu(phy_if_t, lif_if_t, netstack_t *); -static int ipv6_getlifaddr(phy_if_t, lif_if_t, size_t, - net_ifaddr_t [], void *, netstack_t *); -static phy_if_t ipv6_phygetnext(phy_if_t, netstack_t *); -static phy_if_t ipv6_phylookup(const char *, netstack_t *); -static lif_if_t ipv6_lifgetnext(phy_if_t, lif_if_t, netstack_t *); -static int ipv6_inject(inject_t, net_inject_t *, netstack_t *); -static phy_if_t ipv6_routeto(struct sockaddr *, netstack_t *); -static int ipv6_isvalidchecksum(mblk_t *); +static int ip_getifname(net_handle_t, phy_if_t, char *, + const size_t); +static int ip_getmtu(net_handle_t, phy_if_t, lif_if_t); +static int ip_getpmtuenabled(net_handle_t); +static int ip_getlifaddr(net_handle_t, phy_if_t, lif_if_t, + size_t, net_ifaddr_t [], void *); +static phy_if_t ip_phygetnext(net_handle_t, phy_if_t); +static phy_if_t ip_phylookup(net_handle_t, const char *); +static lif_if_t ip_lifgetnext(net_handle_t, phy_if_t, lif_if_t); +static int ip_inject(net_handle_t, inject_t, net_inject_t *); +static phy_if_t ip_routeto(net_handle_t, struct sockaddr *, + struct sockaddr *); +static int ip_ispartialchecksum(net_handle_t, mblk_t *); +static int ip_isvalidchecksum(net_handle_t, mblk_t *); + +static int ipv6_getifname(net_handle_t, phy_if_t, char *, + const size_t); +static int ipv6_getmtu(net_handle_t, phy_if_t, lif_if_t); +static int ipv6_getlifaddr(net_handle_t, phy_if_t, lif_if_t, + size_t, net_ifaddr_t [], void *); +static phy_if_t ipv6_phygetnext(net_handle_t, phy_if_t); +static phy_if_t ipv6_phylookup(net_handle_t, const char *); +static lif_if_t ipv6_lifgetnext(net_handle_t, phy_if_t, lif_if_t); +static int ipv6_inject(net_handle_t, inject_t, net_inject_t *); +static phy_if_t ipv6_routeto(net_handle_t, struct sockaddr *, + struct sockaddr *); +static int ipv6_isvalidchecksum(net_handle_t, mblk_t *); /* Netinfo private functions */ static int ip_getifname_impl(phy_if_t, char *, - const size_t, boolean_t, ip_stack_t *); + const size_t, boolean_t, ip_stack_t *); static int ip_getmtu_impl(phy_if_t, lif_if_t, boolean_t, - ip_stack_t *); + ip_stack_t *); static phy_if_t ip_phylookup_impl(const char *, boolean_t, - ip_stack_t *ipst); + ip_stack_t *); static lif_if_t ip_lifgetnext_impl(phy_if_t, lif_if_t, boolean_t, - ip_stack_t *ipst); + ip_stack_t *); static int ip_inject_impl(inject_t, net_inject_t *, boolean_t, - ip_stack_t *); + ip_stack_t *); static int ip_getifaddr_type(sa_family_t, ipif_t *, lif_if_t, void *); -static phy_if_t ip_routeto_impl(struct sockaddr *, ip_stack_t *); +static phy_if_t ip_routeto_impl(struct sockaddr *, struct sockaddr *, + ip_stack_t *); static int ip_getlifaddr_impl(sa_family_t, phy_if_t, lif_if_t, size_t, net_ifaddr_t [], struct sockaddr *, ip_stack_t *); @@ -102,7 +104,7 @@ static void ip_ni_queue_out_func(void *); static void ip_ni_queue_func_impl(injection_t *, boolean_t); -static net_info_t ipv4info = { +static net_protocol_t ipv4info = { NETINFO_VERSION, NHF_INET, ip_getifname, @@ -119,7 +121,7 @@ static net_info_t ipv4info = { }; -static net_info_t ipv6info = { +static net_protocol_t ipv6info = { NETINFO_VERSION, NHF_INET6, ipv6_getifname, @@ -206,11 +208,15 @@ ip_net_g_destroy() void ip_net_init(ip_stack_t *ipst, netstack_t *ns) { + netid_t id; + + id = net_getnetidbynetstackid(ns->netstack_stackid); + ASSERT(id != -1); - ipst->ips_ipv4_net_data = net_register_impl(&ipv4info, ns); + ipst->ips_ipv4_net_data = net_protocol_register(id, &ipv4info); ASSERT(ipst->ips_ipv4_net_data != NULL); - ipst->ips_ipv6_net_data = net_register_impl(&ipv6info, ns); + ipst->ips_ipv6_net_data = net_protocol_register(id, &ipv6info); ASSERT(ipst->ips_ipv6_net_data != NULL); } @@ -222,12 +228,12 @@ void ip_net_destroy(ip_stack_t *ipst) { if (ipst->ips_ipv4_net_data != NULL) { - if (net_unregister(ipst->ips_ipv4_net_data) == 0) + if (net_protocol_unregister(ipst->ips_ipv4_net_data) == 0) ipst->ips_ipv4_net_data = NULL; } if (ipst->ips_ipv6_net_data != NULL) { - if (net_unregister(ipst->ips_ipv6_net_data) == 0) + if (net_protocol_unregister(ipst->ips_ipv6_net_data) == 0) ipst->ips_ipv6_net_data = NULL; } } @@ -239,59 +245,59 @@ void ipv4_hook_init(ip_stack_t *ipst) { HOOK_FAMILY_INIT(&ipst->ips_ipv4root, Hn_IPV4); - if (net_register_family(ipst->ips_ipv4_net_data, &ipst->ips_ipv4root) + if (net_family_register(ipst->ips_ipv4_net_data, &ipst->ips_ipv4root) != 0) { cmn_err(CE_NOTE, "ipv4_hook_init: " - "net_register_family failed for ipv4"); + "net_family_register failed for ipv4"); } HOOK_EVENT_INIT(&ipst->ips_ip4_physical_in_event, NH_PHYSICAL_IN); - ipst->ips_ipv4firewall_physical_in = net_register_event( + ipst->ips_ipv4firewall_physical_in = net_event_register( ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_in_event); if (ipst->ips_ipv4firewall_physical_in == NULL) { cmn_err(CE_NOTE, "ipv4_hook_init: " - "net_register_event failed for ipv4/physical_in"); + "net_event_register failed for ipv4/physical_in"); } HOOK_EVENT_INIT(&ipst->ips_ip4_physical_out_event, NH_PHYSICAL_OUT); - ipst->ips_ipv4firewall_physical_out = net_register_event( + ipst->ips_ipv4firewall_physical_out = net_event_register( ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_out_event); if (ipst->ips_ipv4firewall_physical_out == NULL) { cmn_err(CE_NOTE, "ipv4_hook_init: " - "net_register_event failed for ipv4/physical_out"); + "net_event_register failed for ipv4/physical_out"); } HOOK_EVENT_INIT(&ipst->ips_ip4_forwarding_event, NH_FORWARDING); - ipst->ips_ipv4firewall_forwarding = net_register_event( + ipst->ips_ipv4firewall_forwarding = net_event_register( ipst->ips_ipv4_net_data, &ipst->ips_ip4_forwarding_event); if (ipst->ips_ipv4firewall_forwarding == NULL) { cmn_err(CE_NOTE, "ipv4_hook_init: " - "net_register_event failed for ipv4/forwarding"); + "net_event_register failed for ipv4/forwarding"); } HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_in_event, NH_LOOPBACK_IN); - ipst->ips_ipv4firewall_loopback_in = net_register_event( + ipst->ips_ipv4firewall_loopback_in = net_event_register( ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_in_event); if (ipst->ips_ipv4firewall_loopback_in == NULL) { cmn_err(CE_NOTE, "ipv4_hook_init: " - "net_register_event failed for ipv4/loopback_in"); + "net_event_register failed for ipv4/loopback_in"); } HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_out_event, NH_LOOPBACK_OUT); - ipst->ips_ipv4firewall_loopback_out = net_register_event( + ipst->ips_ipv4firewall_loopback_out = net_event_register( ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_out_event); if (ipst->ips_ipv4firewall_loopback_out == NULL) { cmn_err(CE_NOTE, "ipv4_hook_init: " - "net_register_event failed for ipv4/loopback_out"); + "net_event_register failed for ipv4/loopback_out"); } HOOK_EVENT_INIT(&ipst->ips_ip4_nic_events, NH_NIC_EVENTS); ipst->ips_ip4_nic_events.he_flags = HOOK_RDONLY; - ipst->ips_ipv4nicevents = net_register_event( + ipst->ips_ipv4nicevents = net_event_register( ipst->ips_ipv4_net_data, &ipst->ips_ip4_nic_events); if (ipst->ips_ipv4nicevents == NULL) { cmn_err(CE_NOTE, "ipv4_hook_init: " - "net_register_event failed for ipv4/nic_events"); + "net_event_register failed for ipv4/nic_events"); } } @@ -299,42 +305,42 @@ void ipv4_hook_destroy(ip_stack_t *ipst) { if (ipst->ips_ipv4firewall_forwarding != NULL) { - if (net_unregister_event(ipst->ips_ipv4_net_data, + if (net_event_unregister(ipst->ips_ipv4_net_data, &ipst->ips_ip4_forwarding_event) == 0) ipst->ips_ipv4firewall_forwarding = NULL; } if (ipst->ips_ipv4firewall_physical_in != NULL) { - if (net_unregister_event(ipst->ips_ipv4_net_data, + if (net_event_unregister(ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_in_event) == 0) ipst->ips_ipv4firewall_physical_in = NULL; } if (ipst->ips_ipv4firewall_physical_out != NULL) { - if (net_unregister_event(ipst->ips_ipv4_net_data, + if (net_event_unregister(ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_out_event) == 0) ipst->ips_ipv4firewall_physical_out = NULL; } if (ipst->ips_ipv4firewall_loopback_in != NULL) { - if (net_unregister_event(ipst->ips_ipv4_net_data, + if (net_event_unregister(ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_in_event) == 0) ipst->ips_ipv4firewall_loopback_in = NULL; } if (ipst->ips_ipv4firewall_loopback_out != NULL) { - if (net_unregister_event(ipst->ips_ipv4_net_data, + if (net_event_unregister(ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_out_event) == 0) ipst->ips_ipv4firewall_loopback_out = NULL; } if (ipst->ips_ipv4nicevents != NULL) { - if (net_unregister_event(ipst->ips_ipv4_net_data, + if (net_event_unregister(ipst->ips_ipv4_net_data, &ipst->ips_ip4_nic_events) == 0) ipst->ips_ipv4nicevents = NULL; } - (void) net_unregister_family(ipst->ips_ipv4_net_data, + (void) net_family_unregister(ipst->ips_ipv4_net_data, &ipst->ips_ipv4root); } @@ -346,59 +352,59 @@ ipv6_hook_init(ip_stack_t *ipst) { HOOK_FAMILY_INIT(&ipst->ips_ipv6root, Hn_IPV6); - if (net_register_family(ipst->ips_ipv6_net_data, &ipst->ips_ipv6root) + if (net_family_register(ipst->ips_ipv6_net_data, &ipst->ips_ipv6root) != 0) { cmn_err(CE_NOTE, "ipv6_hook_init: " - "net_register_family failed for ipv6"); + "net_family_register failed for ipv6"); } HOOK_EVENT_INIT(&ipst->ips_ip6_physical_in_event, NH_PHYSICAL_IN); - ipst->ips_ipv6firewall_physical_in = net_register_event( + ipst->ips_ipv6firewall_physical_in = net_event_register( ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_in_event); if (ipst->ips_ipv6firewall_physical_in == NULL) { cmn_err(CE_NOTE, "ipv6_hook_init: " - "net_register_event failed for ipv6/physical_in"); + "net_event_register failed for ipv6/physical_in"); } HOOK_EVENT_INIT(&ipst->ips_ip6_physical_out_event, NH_PHYSICAL_OUT); - ipst->ips_ipv6firewall_physical_out = net_register_event( + ipst->ips_ipv6firewall_physical_out = net_event_register( ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_out_event); if (ipst->ips_ipv6firewall_physical_out == NULL) { cmn_err(CE_NOTE, "ipv6_hook_init: " - "net_register_event failed for ipv6/physical_out"); + "net_event_register failed for ipv6/physical_out"); } HOOK_EVENT_INIT(&ipst->ips_ip6_forwarding_event, NH_FORWARDING); - ipst->ips_ipv6firewall_forwarding = net_register_event( + ipst->ips_ipv6firewall_forwarding = net_event_register( ipst->ips_ipv6_net_data, &ipst->ips_ip6_forwarding_event); if (ipst->ips_ipv6firewall_forwarding == NULL) { cmn_err(CE_NOTE, "ipv6_hook_init: " - "net_register_event failed for ipv6/forwarding"); + "net_event_register failed for ipv6/forwarding"); } HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_in_event, NH_LOOPBACK_IN); - ipst->ips_ipv6firewall_loopback_in = net_register_event( + ipst->ips_ipv6firewall_loopback_in = net_event_register( ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_in_event); if (ipst->ips_ipv6firewall_loopback_in == NULL) { cmn_err(CE_NOTE, "ipv6_hook_init: " - "net_register_event failed for ipv6/loopback_in"); + "net_event_register failed for ipv6/loopback_in"); } HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_out_event, NH_LOOPBACK_OUT); - ipst->ips_ipv6firewall_loopback_out = net_register_event( + ipst->ips_ipv6firewall_loopback_out = net_event_register( ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_out_event); if (ipst->ips_ipv6firewall_loopback_out == NULL) { cmn_err(CE_NOTE, "ipv6_hook_init: " - "net_register_event failed for ipv6/loopback_out"); + "net_event_register failed for ipv6/loopback_out"); } HOOK_EVENT_INIT(&ipst->ips_ip6_nic_events, NH_NIC_EVENTS); ipst->ips_ip6_nic_events.he_flags = HOOK_RDONLY; - ipst->ips_ipv6nicevents = net_register_event( + ipst->ips_ipv6nicevents = net_event_register( ipst->ips_ipv6_net_data, &ipst->ips_ip6_nic_events); if (ipst->ips_ipv6nicevents == NULL) { cmn_err(CE_NOTE, "ipv6_hook_init: " - "net_register_event failed for ipv6/nic_events"); + "net_event_register failed for ipv6/nic_events"); } } @@ -406,42 +412,42 @@ void ipv6_hook_destroy(ip_stack_t *ipst) { if (ipst->ips_ipv6firewall_forwarding != NULL) { - if (net_unregister_event(ipst->ips_ipv6_net_data, + if (net_event_unregister(ipst->ips_ipv6_net_data, &ipst->ips_ip6_forwarding_event) == 0) ipst->ips_ipv6firewall_forwarding = NULL; } if (ipst->ips_ipv6firewall_physical_in != NULL) { - if (net_unregister_event(ipst->ips_ipv6_net_data, + if (net_event_unregister(ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_in_event) == 0) ipst->ips_ipv6firewall_physical_in = NULL; } if (ipst->ips_ipv6firewall_physical_out != NULL) { - if (net_unregister_event(ipst->ips_ipv6_net_data, + if (net_event_unregister(ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_out_event) == 0) ipst->ips_ipv6firewall_physical_out = NULL; } if (ipst->ips_ipv6firewall_loopback_in != NULL) { - if (net_unregister_event(ipst->ips_ipv6_net_data, + if (net_event_unregister(ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_in_event) == 0) ipst->ips_ipv6firewall_loopback_in = NULL; } if (ipst->ips_ipv6firewall_loopback_out != NULL) { - if (net_unregister_event(ipst->ips_ipv6_net_data, + if (net_event_unregister(ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_out_event) == 0) ipst->ips_ipv6firewall_loopback_out = NULL; } if (ipst->ips_ipv6nicevents != NULL) { - if (net_unregister_event(ipst->ips_ipv6_net_data, + if (net_event_unregister(ipst->ips_ipv6_net_data, &ipst->ips_ip6_nic_events) == 0) ipst->ips_ipv6nicevents = NULL; } - (void) net_unregister_family(ipst->ips_ipv6_net_data, + (void) net_family_unregister(ipst->ips_ipv6_net_data, &ipst->ips_ipv6root); } @@ -449,22 +455,22 @@ ipv6_hook_destroy(ip_stack_t *ipst) * Determine the name of an IPv4 interface */ static int -ip_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen, - netstack_t *ns) +ip_getifname(net_handle_t neti, phy_if_t phy_ifdata, char *buffer, + const size_t buflen) { return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_FALSE, - ns->netstack_ip)); + neti->netd_stack->nts_netstack->netstack_ip)); } /* * Determine the name of an IPv6 interface */ static int -ipv6_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen, - netstack_t *ns) +ipv6_getifname(net_handle_t neti, phy_if_t phy_ifdata, char *buffer, + const size_t buflen) { return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_TRUE, - ns->netstack_ip)); + neti->netd_stack->nts_netstack->netstack_ip)); } /* @@ -509,8 +515,11 @@ ip_getifname_impl(phy_if_t phy_ifdata, * Determine the MTU of an IPv4 network interface */ static int -ip_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) +ip_getmtu(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ip_getmtu_impl(phy_ifdata, ifdata, B_FALSE, ns->netstack_ip)); } @@ -519,8 +528,11 @@ ip_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) * Determine the MTU of an IPv6 network interface */ static int -ipv6_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) +ipv6_getmtu(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ip_getmtu_impl(phy_ifdata, ifdata, B_TRUE, ns->netstack_ip)); } @@ -577,10 +589,13 @@ ip_getmtu_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6, * Determine if path MTU discovery is enabled for IP */ static int -ip_getpmtuenabled(netstack_t *ns) +ip_getpmtuenabled(net_handle_t neti) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); - return ((ns->netstack_ip)->ips_ip_path_mtu_discovery); + return (ns->netstack_ip->ips_ip_path_mtu_discovery); } /* @@ -590,8 +605,11 @@ ip_getpmtuenabled(netstack_t *ns) * But IP Filter does not use this function. */ static phy_if_t -ip_phygetnext(phy_if_t phy_ifdata, netstack_t *ns) +ip_phygetnext(net_handle_t neti, phy_if_t phy_ifdata) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ill_get_next_ifindex(phy_ifdata, B_FALSE, ns->netstack_ip)); } @@ -600,8 +618,11 @@ ip_phygetnext(phy_if_t phy_ifdata, netstack_t *ns) * Get next interface from the current list of IPv6 physical network interfaces */ static phy_if_t -ipv6_phygetnext(phy_if_t phy_ifdata, netstack_t *ns) +ipv6_phygetnext(net_handle_t neti, phy_if_t phy_ifdata) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ill_get_next_ifindex(phy_ifdata, B_TRUE, ns->netstack_ip)); } @@ -610,8 +631,11 @@ ipv6_phygetnext(phy_if_t phy_ifdata, netstack_t *ns) * Determine if a network interface name exists for IPv4 */ static phy_if_t -ip_phylookup(const char *name, netstack_t *ns) +ip_phylookup(net_handle_t neti, const char *name) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ip_phylookup_impl(name, B_FALSE, ns->netstack_ip)); } @@ -620,8 +644,11 @@ ip_phylookup(const char *name, netstack_t *ns) * Determine if a network interface name exists for IPv6 */ static phy_if_t -ipv6_phylookup(const char *name, netstack_t *ns) +ipv6_phylookup(net_handle_t neti, const char *name) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ip_phylookup_impl(name, B_TRUE, ns->netstack_ip)); } @@ -658,8 +685,11 @@ ip_phylookup_impl(const char *name, boolean_t isv6, ip_stack_t *ipst) * Get next interface from the current list of IPv4 logical network interfaces */ static lif_if_t -ip_lifgetnext(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) +ip_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_FALSE, ns->netstack_ip)); @@ -669,8 +699,11 @@ ip_lifgetnext(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) * Get next interface from the current list of IPv6 logical network interfaces */ static lif_if_t -ipv6_lifgetnext(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns) +ipv6_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_TRUE, ns->netstack_ip)); @@ -744,8 +777,11 @@ ip_lifgetnext_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6, * Inject an IPv4 packet to or from an interface */ static int -ip_inject(inject_t style, net_inject_t *packet, netstack_t *ns) +ip_inject(net_handle_t neti, inject_t style, net_inject_t *packet) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ip_inject_impl(style, packet, B_FALSE, ns->netstack_ip)); } @@ -755,9 +791,11 @@ ip_inject(inject_t style, net_inject_t *packet, netstack_t *ns) * Inject an IPv6 packet to or from an interface */ static int -ipv6_inject(inject_t style, net_inject_t *packet, netstack_t *ns) +ipv6_inject(net_handle_t neti, inject_t style, net_inject_t *packet) { - ASSERT(ns != NULL); + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; return (ip_inject_impl(style, packet, B_TRUE, ns->netstack_ip)); } @@ -944,51 +982,68 @@ ip_inject_impl(inject_t style, net_inject_t *packet, boolean_t isv6, * Find the interface used for traffic to a given IPv4 address */ static phy_if_t -ip_routeto(struct sockaddr *address, netstack_t *ns) +ip_routeto(net_handle_t neti, struct sockaddr *address, struct sockaddr *next) { + netstack_t *ns; + ASSERT(address != NULL); - ASSERT(ns != NULL); if (address->sa_family != AF_INET) return (0); - return (ip_routeto_impl(address, ns->netstack_ip)); + + ns = neti->netd_stack->nts_netstack; + ASSERT(ns != NULL); + + return (ip_routeto_impl(address, next, ns->netstack_ip)); } /* * Find the interface used for traffic to a given IPv6 address */ static phy_if_t -ipv6_routeto(struct sockaddr *address, netstack_t *ns) +ipv6_routeto(net_handle_t neti, struct sockaddr *address, struct sockaddr *next) { + netstack_t *ns; + ASSERT(address != NULL); - ASSERT(ns != NULL); if (address->sa_family != AF_INET6) return (0); - return (ip_routeto_impl(address, ns->netstack_ip)); + + ns = neti->netd_stack->nts_netstack; + ASSERT(ns != NULL); + + return (ip_routeto_impl(address, next, ns->netstack_ip)); } /* - * Find the interface used for traffic to an address + * Find the interface used for traffic to an address. + * For lint reasons, next/next6/sin/sin6 are all declared and assigned + * a value at the top. The alternative would end up with two bunches + * of assignments, with each bunch setting half to NULL. */ static phy_if_t -ip_routeto_impl(struct sockaddr *address, ip_stack_t *ipst) +ip_routeto_impl(struct sockaddr *address, struct sockaddr *nexthop, + ip_stack_t *ipst) { + struct sockaddr_in6 *next6 = (struct sockaddr_in6 *)nexthop; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address; + struct sockaddr_in *next = (struct sockaddr_in *)nexthop; + struct sockaddr_in *sin = (struct sockaddr_in *)address; + ire_t *sire = NULL; ire_t *ire; ill_t *ill; phy_if_t phy_if; if (address->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address; ire = ire_route_lookup_v6(&sin6->sin6_addr, NULL, - 0, 0, NULL, NULL, ALL_ZONES, NULL, + 0, 0, NULL, &sire, ALL_ZONES, NULL, MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE, ipst); } else { - struct sockaddr_in *sin = (struct sockaddr_in *)address; ire = ire_route_lookup(sin->sin_addr.s_addr, 0, - 0, 0, NULL, NULL, ALL_ZONES, NULL, + 0, 0, NULL, &sire, ALL_ZONES, NULL, MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE, ipst); } @@ -996,14 +1051,40 @@ ip_routeto_impl(struct sockaddr *address, ip_stack_t *ipst) if (ire == NULL) return (0); + /* + * For some destinations, we have routes that are dead ends, so + * return to indicate that no physical interface can be used to + * reach the destination. + */ + if ((ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE)) != 0) { + if (sire != NULL) + ire_refrele(sire); + ire_refrele(ire); + return (0); + } + ill = ire_to_ill(ire); if (ill == NULL) { + if (sire != NULL) + ire_refrele(sire); ire_refrele(ire); return (0); } + if (nexthop != NULL) { + if (address->sa_family == AF_INET6) { + next->sin_addr.s_addr = sire ? sire->ire_gateway_addr : + sin->sin_addr.s_addr; + } else { + next6->sin6_addr = sire ? sire->ire_gateway_addr_v6 : + sin6->sin6_addr; + } + } + ASSERT(ill != NULL); phy_if = (phy_if_t)ill->ill_phyint->phyint_hook_ifindex; + if (sire != NULL) + ire_refrele(sire); ire_refrele(ire); return (phy_if); @@ -1018,8 +1099,9 @@ ip_routeto_impl(struct sockaddr *address, ip_stack_t *ipst) * NET_HCK_L4_FULL: full layer 4 checksum * NET_HCK_L4_PART: partial layer 4 checksum */ +/*ARGSUSED*/ static int -ip_ispartialchecksum(mblk_t *mp) +ip_ispartialchecksum(net_handle_t neti, mblk_t *mp) { int ret = 0; @@ -1048,8 +1130,9 @@ ip_ispartialchecksum(mblk_t *mp) * 0: the checksum was incorrect * 1: the original checksum was correct */ +/*ARGSUSED*/ static int -ip_isvalidchecksum(mblk_t *mp) +ip_isvalidchecksum(net_handle_t neti, mblk_t *mp) { unsigned char *wptr; ipha_t *ipha = (ipha_t *)mp->b_rptr; @@ -1097,7 +1180,7 @@ ip_isvalidchecksum(mblk_t *mp) */ /*ARGSUSED*/ static int -ipv6_isvalidchecksum(mblk_t *mp) +ipv6_isvalidchecksum(net_handle_t neti, mblk_t *mp) { return (-1); } @@ -1106,9 +1189,12 @@ ipv6_isvalidchecksum(mblk_t *mp) * Determine the network addresses for an IPv4 interface */ static int -ip_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem, - net_ifaddr_t type[], void *storage, netstack_t *ns) +ip_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata, + size_t nelem, net_ifaddr_t type[], void *storage) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ip_getlifaddr_impl(AF_INET, phy_ifdata, ifdata, nelem, type, storage, ns->netstack_ip)); @@ -1118,9 +1204,12 @@ ip_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem, * Determine the network addresses for an IPv6 interface */ static int -ipv6_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem, - net_ifaddr_t type[], void *storage, netstack_t *ns) +ipv6_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata, + size_t nelem, net_ifaddr_t type[], void *storage) { + netstack_t *ns; + + ns = neti->netd_stack->nts_netstack; ASSERT(ns != NULL); return (ip_getlifaddr_impl(AF_INET6, phy_ifdata, ifdata, nelem, type, storage, ns->netstack_ip)); @@ -1338,18 +1427,29 @@ ip_ni_queue_func_impl(injection_t *inject, boolean_t out) void ip_ne_queue_func(void *arg) { - hook_event_int_t *hr; - hook_nic_event_t *info = (hook_nic_event_t *)arg; - netstack_t *ns = info->hne_family->netd_netstack; - ip_stack_t *ipst = ns->netstack_ip; + hook_event_token_t hr; + hook_nic_event_int_t *info = (hook_nic_event_int_t *)arg; + ip_stack_t *ipst; + netstack_t *ns; - hr = (info->hne_family == ipst->ips_ipv6_net_data) ? - ipst->ips_ipv6nicevents : ipst->ips_ipv4nicevents; - (void) hook_run(hr, (hook_data_t)info, ns); + ns = netstack_find_by_stackid(info->hnei_stackid); + if (ns == NULL) + goto done; + + ipst = ns->netstack_ip; + if (ipst == NULL) + goto done; - if (info->hne_data != NULL) - kmem_free(info->hne_data, info->hne_datalen); - kmem_free(arg, sizeof (hook_nic_event_t)); + hr = (info->hnei_event.hne_protocol == ipst->ips_ipv6_net_data) ? + ipst->ips_ipv6nicevents : ipst->ips_ipv4nicevents; + (void) hook_run(info->hnei_event.hne_protocol->netd_hooks, hr, + (hook_data_t)&info->hnei_event); + +done: + if (ns != NULL) + netstack_rele(ns); + kmem_free(info->hnei_event.hne_data, info->hnei_event.hne_datalen); + kmem_free(arg, sizeof (hook_nic_event_int_t)); } /* diff --git a/usr/src/uts/common/inet/ip_stack.h b/usr/src/uts/common/inet/ip_stack.h index 371027e061..48eeea10dd 100644 --- a/usr/src/uts/common/inet/ip_stack.h +++ b/usr/src/uts/common/inet/ip_stack.h @@ -27,8 +27,6 @@ #ifndef _INET_IP_STACK_H #define _INET_IP_STACK_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -412,8 +410,8 @@ struct ip_stack { hook_event_token_t ips_ipv6firewall_loopback_out; hook_event_token_t ips_ipv6nicevents; - net_data_t ips_ipv4_net_data; - net_data_t ips_ipv6_net_data; + net_handle_t ips_ipv4_net_data; + net_handle_t ips_ipv6_net_data; }; typedef struct ip_stack ip_stack_t; diff --git a/usr/src/uts/common/inet/ipf/fil.c b/usr/src/uts/common/inet/ipf/fil.c index a97089a7be..253c60df58 100644 --- a/usr/src/uts/common/inet/ipf/fil.c +++ b/usr/src/uts/common/inet/ipf/fil.c @@ -5651,7 +5651,7 @@ fr_info_t *fin; ipf_stack_t *ifs = fin->fin_ifs; #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - net_data_t net_data_p; + net_handle_t net_data_p; if (fin->fin_v == 4) net_data_p = ifs->ifs_ipf_ipv4; else diff --git a/usr/src/uts/common/inet/ipf/ip_auth.c b/usr/src/uts/common/inet/ipf/ip_auth.c index 9c03e9e0c9..2bdd66fee3 100644 --- a/usr/src/uts/common/inet/ipf/ip_auth.c +++ b/usr/src/uts/common/inet/ipf/ip_auth.c @@ -368,7 +368,7 @@ ipf_stack_t *ifs; frauth_t auth, *au = &auth, *fra; int i, error = 0, len; char *t; - net_data_t net_data_p; + net_handle_t net_data_p; net_inject_t inj_data; int ret; diff --git a/usr/src/uts/common/inet/ipf/ip_fil_solaris.c b/usr/src/uts/common/inet/ipf/ip_fil_solaris.c index ac71544d9a..24c3755eb0 100644 --- a/usr/src/uts/common/inet/ipf/ip_fil_solaris.c +++ b/usr/src/uts/common/inet/ipf/ip_fil_solaris.c @@ -65,30 +65,24 @@ static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21 static int frzerostats __P((caddr_t, ipf_stack_t *)); static int fr_setipfloopback __P((int, ipf_stack_t *)); -static int fr_enableipf __P((ipf_stack_t *, netstack_t *, int)); +static int fr_enableipf __P((ipf_stack_t *, int)); static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); -static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, - netstack_t *)); -static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, - netstack_t *)); -static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, - netstack_t *)); -static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, - netstack_t *)); +static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *)); +static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *)); +static int ipf_hook __P((hook_data_t, int, int, void *)); +static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *)); +static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *)); static int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t, - netstack_t *)); -static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, - netstack_t *)); -static int ipf_hook4 __P((hook_data_t, int, int, netstack_t *)); -static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, - netstack_t *)); -static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, - netstack_t *)); + void *)); +static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *)); +static int ipf_hook4 __P((hook_data_t, int, int, void *)); +static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *)); +static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *)); static int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t, - netstack_t *)); + void *)); static int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t, - netstack_t *)); -static int ipf_hook6 __P((hook_data_t, int, int, netstack_t *)); + void *)); +static int ipf_hook6 __P((hook_data_t, int, int, void *)); extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *)); @@ -140,43 +134,47 @@ ipf_stack_t *ifs; #endif /* - * This lock needs to be dropped around the net_unregister_hook calls + * This lock needs to be dropped around the net_hook_unregister calls * because we can deadlock here with: * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) */ RWLOCK_EXIT(&ifs->ifs_ipf_global); +#define UNDO_HOOK(_f, _b, _e, _h) \ + do { \ + if (ifs->_f != NULL) { \ + if (ifs->_b) { \ + ifs->_b = (net_hook_unregister(ifs->_f, \ + _e, ifs->_h) != 0); \ + if (!ifs->_b) { \ + hook_free(ifs->_h); \ + ifs->_h = NULL; \ + } \ + } else if (ifs->_h != NULL) { \ + hook_free(ifs->_h); \ + ifs->_h = NULL; \ + } \ + } \ + _NOTE(CONSTCOND) \ + } while (0) + /* * Remove IPv6 Hooks */ if (ifs->ifs_ipf_ipv6 != NULL) { - if (ifs->ifs_hook6_physical_in) { - ifs->ifs_hook6_physical_in = (net_unregister_hook(ifs->ifs_ipf_ipv6, - NH_PHYSICAL_IN, &ifs->ifs_ipfhook6_in) != 0); - } - if (ifs->ifs_hook6_physical_out) { - ifs->ifs_hook6_physical_out = - (net_unregister_hook(ifs->ifs_ipf_ipv6, - NH_PHYSICAL_OUT, &ifs->ifs_ipfhook6_out) != 0); - } - if (ifs->ifs_hook6_nic_events) { - ifs->ifs_hook6_nic_events = - (net_unregister_hook(ifs->ifs_ipf_ipv6, - NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0); - } - if (ifs->ifs_hook6_loopback_in) { - ifs->ifs_hook6_loopback_in = - (net_unregister_hook(ifs->ifs_ipf_ipv6, - NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) != 0); - } - if (ifs->ifs_hook6_loopback_out) { - ifs->ifs_hook6_loopback_out = - (net_unregister_hook(ifs->ifs_ipf_ipv6, - NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) != 0); - } - - if (net_release(ifs->ifs_ipf_ipv6) != 0) + UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in, + NH_PHYSICAL_IN, ifs_ipfhook6_in); + UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out, + NH_PHYSICAL_OUT, ifs_ipfhook6_out); + UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events, + NH_NIC_EVENTS, ifs_ipfhook6_nicevents); + UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in, + NH_LOOPBACK_IN, ifs_ipfhook6_loop_in); + UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out, + NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out); + + if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0) goto detach_failed; ifs->ifs_ipf_ipv6 = NULL; } @@ -185,37 +183,24 @@ ipf_stack_t *ifs; * Remove IPv4 Hooks */ if (ifs->ifs_ipf_ipv4 != NULL) { - if (ifs->ifs_hook4_physical_in) { - ifs->ifs_hook4_physical_in = - (net_unregister_hook(ifs->ifs_ipf_ipv4, - NH_PHYSICAL_IN, &ifs->ifs_ipfhook4_in) != 0); - } - if (ifs->ifs_hook4_physical_out) { - ifs->ifs_hook4_physical_out = - (net_unregister_hook(ifs->ifs_ipf_ipv4, - NH_PHYSICAL_OUT, &ifs->ifs_ipfhook4_out) != 0); - } - if (ifs->ifs_hook4_nic_events) { - ifs->ifs_hook4_nic_events = - (net_unregister_hook(ifs->ifs_ipf_ipv4, - NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0); - } - if (ifs->ifs_hook4_loopback_in) { - ifs->ifs_hook4_loopback_in = - (net_unregister_hook(ifs->ifs_ipf_ipv4, - NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) != 0); - } - if (ifs->ifs_hook4_loopback_out) { - ifs->ifs_hook4_loopback_out = - (net_unregister_hook(ifs->ifs_ipf_ipv4, - NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) != 0); - } - - if (net_release(ifs->ifs_ipf_ipv4) != 0) + UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in, + NH_PHYSICAL_IN, ifs_ipfhook4_in); + UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out, + NH_PHYSICAL_OUT, ifs_ipfhook4_out); + UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events, + NH_NIC_EVENTS, ifs_ipfhook4_nicevents); + UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in, + NH_LOOPBACK_IN, ifs_ipfhook4_loop_in); + UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out, + NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out); + + if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0) goto detach_failed; ifs->ifs_ipf_ipv4 = NULL; } +#undef UNDO_HOOK + #ifdef IPFDEBUG cmn_err(CE_CONT, "ipldetach()\n"); #endif @@ -234,10 +219,11 @@ ipf_stack_t *ifs; ifs->ifs_ipf_locks_done = 0; } - if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || ifs->ifs_hook4_nic_events || - ifs->ifs_hook4_loopback_in || ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || - ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || ifs->ifs_hook6_loopback_in || - ifs->ifs_hook6_loopback_out) + if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || + ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in || + ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || + ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || + ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out) return -1; return 0; @@ -247,13 +233,13 @@ detach_failed: return -1; } -int iplattach(ifs, ns) +int iplattach(ifs) ipf_stack_t *ifs; -netstack_t *ns; { #if SOLARIS2 < 10 int i; #endif + netid_t id = ifs->ifs_netid; #ifdef IPFDEBUG cmn_err(CE_CONT, "iplattach()\n"); @@ -283,17 +269,19 @@ netstack_t *ns; if (fr_initialise(ifs) < 0) return -1; - HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v4, - "ipfilter_hook_nicevents"); - HOOK_INIT(&ifs->ifs_ipfhook4_in, ipf_hook4_in, "ipfilter_hook_in"); - HOOK_INIT(&ifs->ifs_ipfhook4_out, ipf_hook4_out, "ipfilter_hook_out"); - HOOK_INIT(&ifs->ifs_ipfhook4_loop_in, ipf_hook4_in, - "ipfilter_hook_loop_in"); - HOOK_INIT(&ifs->ifs_ipfhook4_loop_out, ipf_hook4_out, - "ipfilter_hook_loop_out"); + HOOK_INIT(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4, + "ipfilter_hook4_nicevents", ifs); + HOOK_INIT(ifs->ifs_ipfhook4_in, ipf_hook4_in, + "ipfilter_hook4_in", ifs); + HOOK_INIT(ifs->ifs_ipfhook4_out, ipf_hook4_out, + "ipfilter_hook4_out", ifs); + HOOK_INIT(ifs->ifs_ipfhook4_loop_in, ipf_hook4_in, + "ipfilter_hook4_loop_in", ifs); + HOOK_INIT(ifs->ifs_ipfhook4_loop_out, ipf_hook4_out, + "ipfilter_hook4_loop_out", ifs); /* - * If we hold this lock over all of the net_register_hook calls, we + * If we hold this lock over all of the net_hook_register calls, we * can cause a deadlock to occur with the following lock ordering: * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) @@ -303,79 +291,81 @@ netstack_t *ns; /* * Add IPv4 hooks */ - ifs->ifs_ipf_ipv4 = net_lookup_impl(NHF_INET, ns); + ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET); if (ifs->ifs_ipf_ipv4 == NULL) goto hookup_failed; - ifs->ifs_hook4_nic_events = (net_register_hook(ifs->ifs_ipf_ipv4, - NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); + ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4, + NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0); if (!ifs->ifs_hook4_nic_events) goto hookup_failed; - ifs->ifs_hook4_physical_in = (net_register_hook(ifs->ifs_ipf_ipv4, - NH_PHYSICAL_IN, &ifs->ifs_ipfhook4_in) == 0); + ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4, + NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0); if (!ifs->ifs_hook4_physical_in) goto hookup_failed; - ifs->ifs_hook4_physical_out = (net_register_hook(ifs->ifs_ipf_ipv4, - NH_PHYSICAL_OUT, &ifs->ifs_ipfhook4_out) == 0); + ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4, + NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0); if (!ifs->ifs_hook4_physical_out) goto hookup_failed; if (ifs->ifs_ipf_loopback) { - ifs->ifs_hook4_loopback_in = - (net_register_hook(ifs->ifs_ipf_ipv4, - NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) == 0); + ifs->ifs_hook4_loopback_in = (net_hook_register( + ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, + ifs->ifs_ipfhook4_loop_in) == 0); if (!ifs->ifs_hook4_loopback_in) goto hookup_failed; - ifs->ifs_hook4_loopback_out = - (net_register_hook(ifs->ifs_ipf_ipv4, - NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) == 0); + ifs->ifs_hook4_loopback_out = (net_hook_register( + ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, + ifs->ifs_ipfhook4_loop_out) == 0); if (!ifs->ifs_hook4_loopback_out) goto hookup_failed; } /* * Add IPv6 hooks */ - ifs->ifs_ipf_ipv6 = net_lookup_impl(NHF_INET6, ns); + ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6); if (ifs->ifs_ipf_ipv6 == NULL) goto hookup_failed; - HOOK_INIT(&ifs->ifs_ipfhook6_in, ipf_hook6_in, "ipfilter_hook_in"); - HOOK_INIT(&ifs->ifs_ipfhook6_out, ipf_hook6_out, "ipfilter_hook_out"); - HOOK_INIT(&ifs->ifs_ipfhook6_loop_in, ipf_hook6_in, - "ipfilter_hook_loop_in"); - HOOK_INIT(&ifs->ifs_ipfhook6_loop_out, ipf_hook6_out, - "ipfilter_hook_loop_out"); - - HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v6, - "ipfilter_hook_nicevents"); - ifs->ifs_hook6_nic_events = (net_register_hook(ifs->ifs_ipf_ipv6, - NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); + HOOK_INIT(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6, + "ipfilter_hook6_nicevents", ifs); + HOOK_INIT(ifs->ifs_ipfhook6_in, ipf_hook6_in, + "ipfilter_hook6_in", ifs); + HOOK_INIT(ifs->ifs_ipfhook6_out, ipf_hook6_out, + "ipfilter_hook6_out", ifs); + HOOK_INIT(ifs->ifs_ipfhook6_loop_in, ipf_hook6_in, + "ipfilter_hook6_loop_in", ifs); + HOOK_INIT(ifs->ifs_ipfhook6_loop_out, ipf_hook6_out, + "ipfilter_hook6_loop_out", ifs); + + ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6, + NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0); if (!ifs->ifs_hook6_nic_events) goto hookup_failed; - ifs->ifs_hook6_physical_in = (net_register_hook(ifs->ifs_ipf_ipv6, - NH_PHYSICAL_IN, &ifs->ifs_ipfhook6_in) == 0); + ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6, + NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0); if (!ifs->ifs_hook6_physical_in) goto hookup_failed; - ifs->ifs_hook6_physical_out = (net_register_hook(ifs->ifs_ipf_ipv6, - NH_PHYSICAL_OUT, &ifs->ifs_ipfhook6_out) == 0); + ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6, + NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0); if (!ifs->ifs_hook6_physical_out) goto hookup_failed; if (ifs->ifs_ipf_loopback) { - ifs->ifs_hook6_loopback_in = - (net_register_hook(ifs->ifs_ipf_ipv6, - NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) == 0); + ifs->ifs_hook6_loopback_in = (net_hook_register( + ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, + ifs->ifs_ipfhook6_loop_in) == 0); if (!ifs->ifs_hook6_loopback_in) goto hookup_failed; - ifs->ifs_hook6_loopback_out = - (net_register_hook(ifs->ifs_ipf_ipv6, - NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) == 0); + ifs->ifs_hook6_loopback_out = (net_hook_register( + ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, + ifs->ifs_ipfhook6_loop_out) == 0); if (!ifs->ifs_hook6_loopback_out) goto hookup_failed; } @@ -453,27 +443,27 @@ ipf_stack_t *ifs; if (set && !ifs->ifs_ipf_loopback) { ifs->ifs_ipf_loopback = 1; - ifs->ifs_hook4_loopback_in = - (net_register_hook(ifs->ifs_ipf_ipv4, - NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) == 0); + ifs->ifs_hook4_loopback_in = (net_hook_register( + ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, + ifs->ifs_ipfhook4_loop_in) == 0); if (!ifs->ifs_hook4_loopback_in) return EINVAL; - ifs->ifs_hook4_loopback_out = - (net_register_hook(ifs->ifs_ipf_ipv4, - NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) == 0); + ifs->ifs_hook4_loopback_out = (net_hook_register( + ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, + ifs->ifs_ipfhook4_loop_out) == 0); if (!ifs->ifs_hook4_loopback_out) return EINVAL; - ifs->ifs_hook6_loopback_in = - (net_register_hook(ifs->ifs_ipf_ipv6, - NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) == 0); + ifs->ifs_hook6_loopback_in = (net_hook_register( + ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, + ifs->ifs_ipfhook6_loop_in) == 0); if (!ifs->ifs_hook6_loopback_in) return EINVAL; - ifs->ifs_hook6_loopback_out = - (net_register_hook(ifs->ifs_ipf_ipv6, - NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) == 0); + ifs->ifs_hook6_loopback_out = (net_hook_register( + ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, + ifs->ifs_ipfhook6_loop_out) == 0); if (!ifs->ifs_hook6_loopback_out) return EINVAL; @@ -481,26 +471,26 @@ ipf_stack_t *ifs; ifs->ifs_ipf_loopback = 0; ifs->ifs_hook4_loopback_in = - (net_unregister_hook(ifs->ifs_ipf_ipv4, - NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) != 0); + (net_hook_unregister(ifs->ifs_ipf_ipv4, + NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); if (ifs->ifs_hook4_loopback_in) return EBUSY; ifs->ifs_hook4_loopback_out = - (net_unregister_hook(ifs->ifs_ipf_ipv4, - NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) != 0); + (net_hook_unregister(ifs->ifs_ipf_ipv4, + NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0); if (ifs->ifs_hook4_loopback_out) return EBUSY; ifs->ifs_hook6_loopback_in = - (net_unregister_hook(ifs->ifs_ipf_ipv6, - NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) != 0); + (net_hook_unregister(ifs->ifs_ipf_ipv6, + NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); if (ifs->ifs_hook6_loopback_in) return EBUSY; ifs->ifs_hook6_loopback_out = - (net_unregister_hook(ifs->ifs_ipf_ipv6, - NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) != 0); + (net_hook_unregister(ifs->ifs_ipf_ipv6, + NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0); if (ifs->ifs_hook6_loopback_out) return EBUSY; } @@ -528,7 +518,6 @@ int *rp; friostat_t fio; minor_t unit; u_int enable; - netstack_t *ns; ipf_stack_t *ifs; #ifdef IPFDEBUG @@ -539,30 +528,31 @@ int *rp; if (IPL_LOGMAX < unit) return ENXIO; - ns = netstack_find_by_cred(cp); - ASSERT(ns != NULL); - ifs = ns->netstack_ipf; + /* + * As we're calling ipf_find_stack in user space, from a given zone + * to find the stack pointer for this zone, there is no need to have + * a hold/refence count here. + */ + ifs = ipf_find_stack(crgetzoneid(cp)); ASSERT(ifs != NULL); if (ifs->ifs_fr_running <= 0) { if (unit != IPL_LOGIPF) { - netstack_rele(ifs->ifs_netstack); return EIO; } if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && cmd != SIOCIPFSET && cmd != SIOCFRENB && cmd != SIOCGETFS && cmd != SIOCGETFF) { - netstack_rele(ifs->ifs_netstack); return EIO; } } READ_ENTER(&ifs->ifs_ipf_global); - error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, curproc, ifs); + error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, + curproc, ifs); if (error != -1) { RWLOCK_EXIT(&ifs->ifs_ipf_global); - netstack_rele(ifs->ifs_netstack); return error; } error = 0; @@ -582,7 +572,7 @@ int *rp; RWLOCK_EXIT(&ifs->ifs_ipf_global); WRITE_ENTER(&ifs->ifs_ipf_global); - error = fr_enableipf(ifs, ns, enable); + error = fr_enableipf(ifs, enable); } break; case SIOCIPFSET : @@ -599,8 +589,9 @@ int *rp; if (!(mode & FWRITE)) error = EPERM; else { - error = COPYIN((caddr_t)data, (caddr_t)&ifs->ifs_fr_flags, - sizeof(ifs->ifs_fr_flags)); + error = COPYIN((caddr_t)data, + (caddr_t)&ifs->ifs_fr_flags, + sizeof(ifs->ifs_fr_flags)); if (error != 0) error = EFAULT; } @@ -615,7 +606,7 @@ int *rp; break; case SIOCGETFF : error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, - sizeof(ifs->ifs_fr_flags)); + sizeof(ifs->ifs_fr_flags)); if (error != 0) error = EFAULT; break; @@ -675,7 +666,7 @@ int *rp; if (!error) { tmp = frflush(unit, 4, tmp, ifs); error = COPYOUT((caddr_t)&tmp, (caddr_t)data, - sizeof(tmp)); + sizeof(tmp)); if (error != 0) error = EFAULT; } else @@ -692,7 +683,7 @@ int *rp; if (!error) { tmp = frflush(unit, 6, tmp, ifs); error = COPYOUT((caddr_t)&tmp, (caddr_t)data, - sizeof(tmp)); + sizeof(tmp)); if (error != 0) error = EFAULT; } else @@ -751,11 +742,13 @@ int *rp; #endif break; case SIOCIPFITER : - error = ipf_frruleiter((caddr_t)data, cp->cr_uid, curproc, ifs); + error = ipf_frruleiter((caddr_t)data, cp->cr_uid, + curproc, ifs); break; case SIOCGENITER : - error = ipf_genericiter((caddr_t)data, cp->cr_uid, curproc, ifs); + error = ipf_genericiter((caddr_t)data, cp->cr_uid, + curproc, ifs); break; case SIOCIPFDELTOK : @@ -768,19 +761,18 @@ int *rp; break; default : - cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", cmd, (void *)data); + cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", + cmd, (void *)data); error = EINVAL; break; } RWLOCK_EXIT(&ifs->ifs_ipf_global); - netstack_rele(ifs->ifs_netstack); return error; } -static int fr_enableipf(ifs, ns, enable) +static int fr_enableipf(ifs, enable) ipf_stack_t *ifs; -netstack_t *ns; int enable; { int error; @@ -789,25 +781,26 @@ int enable; error = ipldetach(ifs); if (error == 0) ifs->ifs_fr_running = -1; - return (error); + return error; } if (ifs->ifs_fr_running > 0) - return (0); + return 0; - error = iplattach(ifs, ns); + error = iplattach(ifs); if (error == 0) { if (ifs->ifs_fr_timer_id == NULL) { int hz = drv_usectohz(500000); ifs->ifs_fr_timer_id = timeout(fr_slowtimer, - (void *)ifs, hz); + (void *)ifs, + hz); } ifs->ifs_fr_running = 1; } else { (void) ipldetach(ifs); } - return (error); + return error; } @@ -816,7 +809,7 @@ char *name; int v; ipf_stack_t *ifs; { - net_data_t nif; + net_handle_t nif; if (v == 4) nif = ifs->ifs_ipf_ipv4; @@ -825,8 +818,6 @@ ipf_stack_t *ifs; else return 0; - nif->netd_netstack = ifs->ifs_netstack; - return (net_phylookup(nif, name)); } @@ -881,13 +872,15 @@ dev_t dev; register struct uio *uio; cred_t *cp; { - netstack_t *ns; ipf_stack_t *ifs; int ret; - ns = netstack_find_by_cred(cp); - ASSERT(ns != NULL); - ifs = ns->netstack_ipf; + /* + * As we're calling ipf_find_stack in user space, from a given zone + * to find the stack pointer for this zone, there is no need to have + * a hold/refence count here. + */ + ifs = ipf_find_stack(crgetzoneid(cp)); ASSERT(ifs != NULL); # ifdef IPFDEBUG @@ -895,19 +888,16 @@ cred_t *cp; # endif if (ifs->ifs_fr_running < 1) { - netstack_rele(ifs->ifs_netstack); return EIO; } # ifdef IPFILTER_SYNC if (getminor(dev) == IPL_LOGSYNC) { - netstack_rele(ifs->ifs_netstack); return ipfsync_read(uio); } # endif ret = ipflog_read(getminor(dev), uio, ifs); - netstack_rele(ifs->ifs_netstack); return ret; } #endif /* IPFILTER_LOG */ @@ -924,12 +914,14 @@ dev_t dev; register struct uio *uio; cred_t *cp; { - netstack_t *ns; ipf_stack_t *ifs; - ns = netstack_find_by_cred(cp); - ASSERT(ns != NULL); - ifs = ns->netstack_ipf; + /* + * As we're calling ipf_find_stack in user space, from a given zone + * to find the stack pointer for this zone, there is no need to have + * a hold/refence count here. + */ + ifs = ipf_find_stack(crgetzoneid(cp)); ASSERT(ifs != NULL); #ifdef IPFDEBUG @@ -937,7 +929,6 @@ cred_t *cp; #endif if (ifs->ifs_fr_running < 1) { - netstack_rele(ifs->ifs_netstack); return EIO; } @@ -948,7 +939,6 @@ cred_t *cp; dev = dev; /* LINT */ uio = uio; /* LINT */ cp = cp; /* LINT */ - netstack_rele(ifs->ifs_netstack); return ENXIO; } @@ -1336,7 +1326,7 @@ ipf_stack_t *ifs; struct sockaddr_in6 v6addr[2]; struct sockaddr_in v4addr[2]; net_ifaddr_t type[2]; - net_data_t net_data; + net_handle_t net_data; phy_if_t phyif; void *array; @@ -1645,7 +1635,7 @@ int len; int fr_verifysrc(fin) fr_info_t *fin; { - net_data_t net_data_p; + net_handle_t net_data_p; phy_if_t phy_ifdata_routeto; struct sockaddr sin; ipf_stack_t *ifs = fin->fin_ifs; @@ -1661,7 +1651,7 @@ fr_info_t *fin; /* Get the index corresponding to the if name */ sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); - phy_ifdata_routeto = net_routeto(net_data_p, &sin); + phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL); return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); } @@ -1694,8 +1684,8 @@ mblk_t *mb, **mpp; fr_info_t *fin; frdest_t *fdp; { - net_data_t net_data_p; - net_inject_t inj_data; + net_handle_t net_data_p; + net_inject_t *inj; mblk_t *mp = NULL; frentry_t *fr = fin->fin_fr; qpktinfo_t *qpi; @@ -1717,6 +1707,10 @@ frdest_t *fdp; return (-1); } + inj = net_inject_alloc(NETINFO_VERSION); + if (inj == NULL) + return -1; + ip = fin->fin_ip; qpi = fin->fin_qpi; @@ -1746,12 +1740,12 @@ frdest_t *fdp; *mpp = mp; } - sinp = (struct sockaddr *)&inj_data.ni_addr; + sinp = (struct sockaddr *)&inj->ni_addr; sin = (struct sockaddr_in *)sinp; sin6 = (struct sockaddr_in6 *)sinp; - bzero((char *)&inj_data.ni_addr, sizeof (inj_data.ni_addr)); - inj_data.ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; - inj_data.ni_packet = mb; + bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr)); + inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; + inj->ni_packet = mb; /* * In case we're here due to "to <if>" being used with @@ -1762,7 +1756,7 @@ frdest_t *fdp; if ((fr != NULL) && (fdp->fd_ifp != NULL) && (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) goto bad_fastroute; - inj_data.ni_physical = (phy_if_t)fdp->fd_ifp; + inj->ni_physical = (phy_if_t)fdp->fd_ifp; if (fin->fin_v == 4) { sin->sin_addr = fdp->fd_ip; } else { @@ -1774,7 +1768,7 @@ frdest_t *fdp; } else { sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; } - inj_data.ni_physical = net_routeto(net_data_p, sinp); + inj->ni_physical = net_routeto(net_data_p, sinp, NULL); } /* @@ -1795,7 +1789,7 @@ frdest_t *fdp; u_32_t pass; saveifp = fin->fin_ifp; - fin->fin_ifp = (void *)inj_data.ni_physical; + fin->fin_ifp = (void *)inj->ni_physical; fin->fin_flx &= ~FI_STATE; fin->fin_out = 1; (void) fr_acctpkt(fin, &pass); @@ -1821,14 +1815,17 @@ frdest_t *fdp; #endif if (net_data_p) { - if (net_inject(net_data_p, NI_DIRECT_OUT, &inj_data) < 0) { + if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) { + net_inject_free(inj); return (-1); } } ifs->ifs_fr_frouteok[0]++; + net_inject_free(inj); return 0; bad_fastroute: + net_inject_free(inj); freemsg(mb); ifs->ifs_fr_frouteok[1]++; return -1; @@ -1836,7 +1833,7 @@ bad_fastroute: /* ------------------------------------------------------------------------ */ -/* Function: ipf_hook_out */ +/* Function: ipf_hook4_out */ /* Returns: int - 0 == packet ok, else problem, free packet if not done */ /* Parameters: event(I) - pointer to event */ /* info(I) - pointer to hook information for firewalling */ @@ -1844,18 +1841,18 @@ bad_fastroute: /* Calling ipf_hook. */ /* ------------------------------------------------------------------------ */ /*ARGSUSED*/ -int ipf_hook4_out(hook_event_token_t token, hook_data_t info, netstack_t *ns) +int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg) { - return ipf_hook4(info, 1, 0, ns); + return ipf_hook(info, 1, 0, arg); } /*ARGSUSED*/ -int ipf_hook6_out(hook_event_token_t token, hook_data_t info, netstack_t *ns) +int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg) { - return ipf_hook6(info, 1, 0, ns); + return ipf_hook6(info, 1, 0, arg); } /* ------------------------------------------------------------------------ */ -/* Function: ipf_hook_in */ +/* Function: ipf_hook4_in */ /* Returns: int - 0 == packet ok, else problem, free packet if not done */ /* Parameters: event(I) - pointer to event */ /* info(I) - pointer to hook information for firewalling */ @@ -1863,19 +1860,19 @@ int ipf_hook6_out(hook_event_token_t token, hook_data_t info, netstack_t *ns) /* Calling ipf_hook. */ /* ------------------------------------------------------------------------ */ /*ARGSUSED*/ -int ipf_hook4_in(hook_event_token_t token, hook_data_t info, netstack_t *ns) +int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg) { - return ipf_hook4(info, 0, 0, ns); + return ipf_hook(info, 0, 0, arg); } /*ARGSUSED*/ -int ipf_hook6_in(hook_event_token_t token, hook_data_t info, netstack_t *ns) +int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg) { - return ipf_hook6(info, 0, 0, ns); + return ipf_hook6(info, 0, 0, arg); } /* ------------------------------------------------------------------------ */ -/* Function: ipf_hook_loop_out */ +/* Function: ipf_hook4_loop_out */ /* Returns: int - 0 == packet ok, else problem, free packet if not done */ /* Parameters: event(I) - pointer to event */ /* info(I) - pointer to hook information for firewalling */ @@ -1883,16 +1880,14 @@ int ipf_hook6_in(hook_event_token_t token, hook_data_t info, netstack_t *ns) /* Calling ipf_hook. */ /* ------------------------------------------------------------------------ */ /*ARGSUSED*/ -int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, - netstack_t *ns) +int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg) { - return ipf_hook4(info, 1, FI_NOCKSUM, ns); + return ipf_hook(info, 1, FI_NOCKSUM, arg); } /*ARGSUSED*/ -int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, - netstack_t *ns) +int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg) { - return ipf_hook6(info, 1, FI_NOCKSUM, ns); + return ipf_hook6(info, 1, FI_NOCKSUM, arg); } /* ------------------------------------------------------------------------ */ @@ -1904,16 +1899,14 @@ int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, /* Calling ipf_hook. */ /* ------------------------------------------------------------------------ */ /*ARGSUSED*/ -int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, - netstack_t *ns) +int ipf_hook_loop_in(hook_event_token_t token, hook_data_t info, void *arg) { - return ipf_hook4(info, 0, FI_NOCKSUM, ns); + return ipf_hook(info, 0, FI_NOCKSUM, arg); } /*ARGSUSED*/ -int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, - netstack_t *ns) +int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg) { - return ipf_hook6(info, 0, FI_NOCKSUM, ns); + return ipf_hook6(info, 0, FI_NOCKSUM, arg); } /* ------------------------------------------------------------------------ */ @@ -1927,15 +1920,17 @@ int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, /* parameters out of the info structure and forms them up to be useful for */ /* calling ipfilter. */ /* ------------------------------------------------------------------------ */ -int ipf_hook4(hook_data_t info, int out, int loopback, netstack_t *ns) +int ipf_hook(hook_data_t info, int out, int loopback, void *arg) { hook_pkt_event_t *fw; - int rval, hlen; + ipf_stack_t *ifs; qpktinfo_t qpi; + int rval, hlen; u_short swap; phy_if_t phy; ip_t *ip; + ifs = arg; fw = (hook_pkt_event_t *)info; ASSERT(fw != NULL); @@ -1958,7 +1953,7 @@ int ipf_hook4(hook_data_t info, int out, int loopback, netstack_t *ns) qpi.qpi_flags |= loopback; rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, - &qpi, fw->hpe_mp, ns->netstack_ipf); + &qpi, fw->hpe_mp, ifs); /* For fastroute cases, fr_check returns 0 with mp set to NULL */ if (rval == 0 && *(fw->hpe_mp) == NULL) @@ -1977,7 +1972,7 @@ int ipf_hook4(hook_data_t info, int out, int loopback, netstack_t *ns) return rval; } -int ipf_hook6(hook_data_t info, int out, int loopback, netstack_t *ns) +int ipf_hook6(hook_data_t info, int out, int loopback, void *arg) { hook_pkt_event_t *fw; int rval, hlen; @@ -2001,7 +1996,7 @@ int ipf_hook6(hook_data_t info, int out, int loopback, netstack_t *ns) qpi.qpi_flags |= loopback; rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, - &qpi, fw->hpe_mp, ns->netstack_ipf); + &qpi, fw->hpe_mp, arg); /* For fastroute cases, fr_check returns 0 with mp set to NULL */ if (rval == 0 && *(fw->hpe_mp) == NULL) @@ -2024,12 +2019,11 @@ int ipf_hook6(hook_data_t info, int out, int loopback, netstack_t *ns) /* Function to receive asynchronous NIC events from IP */ /* ------------------------------------------------------------------------ */ /*ARGSUSED*/ -int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, - netstack_t *ns) +int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg) { struct sockaddr_in *sin; hook_nic_event_t *hn; - ipf_stack_t *ifs = ns->netstack_ipf; + ipf_stack_t *ifs = arg; hn = (hook_nic_event_t *)info; @@ -2085,12 +2079,11 @@ int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, /* Function to receive asynchronous NIC events from IP */ /* ------------------------------------------------------------------------ */ /*ARGSUSED*/ -int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, - netstack_t *ns) +int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg) { struct sockaddr_in6 *sin6; hook_nic_event_t *hn; - ipf_stack_t *ifs = ns->netstack_ipf; + ipf_stack_t *ifs = arg; hn = (hook_nic_event_t *)info; diff --git a/usr/src/uts/common/inet/ipf/ip_log.c b/usr/src/uts/common/inet/ipf/ip_log.c index 57251901aa..1fe54f3a07 100644 --- a/usr/src/uts/common/inet/ipf/ip_log.c +++ b/usr/src/uts/common/inet/ipf/ip_log.c @@ -5,12 +5,10 @@ * * $Id: ip_log.c,v 2.75.2.7 2005/06/11 07:47:44 darrenr Exp $ * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/param.h> #if defined(KERNEL) || defined(_KERNEL) # undef KERNEL @@ -242,7 +240,7 @@ u_int flags; u_char p; mb_t *m; # if SOLARIS && defined(_KERNEL) - net_data_t nif; + net_handle_t nif; void *ifp; # else # if defined(__hpux) && defined(_KERNEL) diff --git a/usr/src/uts/common/inet/ipf/ip_nat.c b/usr/src/uts/common/inet/ipf/ip_nat.c index 0296144195..b7165f92b1 100644 --- a/usr/src/uts/common/inet/ipf/ip_nat.c +++ b/usr/src/uts/common/inet/ipf/ip_nat.c @@ -4129,7 +4129,7 @@ u_32_t nflags; } #if SOLARIS && defined(_KERNEL) - net_data_t net_data_p = ifs->ifs_ipf_ipv4; + net_handle_t net_data_p = ifs->ifs_ipf_ipv4; #endif tcp = NULL; @@ -4459,7 +4459,7 @@ u_32_t nflags; } #if SOLARIS && defined(_KERNEL) - net_data_t net_data_p = ifs->ifs_ipf_ipv4; + net_handle_t net_data_p = ifs->ifs_ipf_ipv4; #endif tcp = NULL; diff --git a/usr/src/uts/common/inet/ipf/ip_nat6.c b/usr/src/uts/common/inet/ipf/ip_nat6.c index 71a4dbd556..9fbfd694c4 100644 --- a/usr/src/uts/common/inet/ipf/ip_nat6.c +++ b/usr/src/uts/common/inet/ipf/ip_nat6.c @@ -7,8 +7,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI"$ - #if defined(KERNEL) || defined(_KERNEL) # undef KERNEL # undef _KERNEL @@ -2220,7 +2218,7 @@ u_32_t nflags; ipf_stack_t *ifs = fin->fin_ifs; #if SOLARIS && defined(_KERNEL) - net_data_t net_data_p = ifs->ifs_ipf_ipv6; + net_handle_t net_data_p = ifs->ifs_ipf_ipv6; #endif tcp = NULL; @@ -2509,7 +2507,7 @@ u_32_t nflags; ipf_stack_t *ifs = fin->fin_ifs; #if SOLARIS && defined(_KERNEL) - net_data_t net_data_p = ifs->ifs_ipf_ipv6; + net_handle_t net_data_p = ifs->ifs_ipf_ipv6; #endif tcp = NULL; diff --git a/usr/src/uts/common/inet/ipf/ip_proxy.c b/usr/src/uts/common/inet/ipf/ip_proxy.c index 9a045ca74f..6f89a77073 100644 --- a/usr/src/uts/common/inet/ipf/ip_proxy.c +++ b/usr/src/uts/common/inet/ipf/ip_proxy.c @@ -490,7 +490,7 @@ nat_t *nat; ipf_stack_t *ifs = fin->fin_ifs; #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - net_data_t net_data_p; + net_handle_t net_data_p; if (fin->fin_v == 4) net_data_p = ifs->ifs_ipf_ipv4; else diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_fil.h b/usr/src/uts/common/inet/ipf/netinet/ip_fil.h index 2763a68a8e..57f6ab4c25 100644 --- a/usr/src/uts/common/inet/ipf/netinet/ip_fil.h +++ b/usr/src/uts/common/inet/ipf/netinet/ip_fil.h @@ -1316,6 +1316,7 @@ extern void ipfilterattach __P((int)); extern int ipl_enable __P((void)); extern int ipl_disable __P((void)); # ifdef MENTAT +extern ipf_stack_t *ipf_find_stack(const zoneid_t zone); extern int fr_check __P((struct ip *, int, void *, int, void *, mblk_t **, ipf_stack_t *)); # if SOLARIS @@ -1419,7 +1420,7 @@ extern int count4bits __P((u_32_t)); extern int count6bits __P((u_32_t *)); extern int frrequest __P((int, ioctlcmd_t, caddr_t, int, int, ipf_stack_t *)); extern char *getifname __P((struct ifnet *)); -extern int iplattach __P((ipf_stack_t *, netstack_t *)); +extern int iplattach __P((ipf_stack_t *)); extern int ipldetach __P((ipf_stack_t *)); extern u_short ipf_cksum __P((u_short *, int)); extern int copyinptr __P((void *, void *, size_t)); diff --git a/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h b/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h index 44ef0ace0f..29302bcc2a 100644 --- a/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h +++ b/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h @@ -7,8 +7,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #ifndef __IPF_STACK_H__ #define __IPF_STACK_H__ @@ -41,7 +39,10 @@ * IPF stack instances */ struct ipf_stack { - netstack_t *ifs_netstack; + struct ipf_stack *ifs_next; + struct ipf_stack **ifs_pnext; + netid_t ifs_netid; + zoneid_t ifs_zone; /* ipf module */ @@ -108,15 +109,16 @@ struct ipf_stack { ipftuneable_t *ifs_ipf_tunelist; /* ip_fil_solaris.c */ - hook_t ifs_ipfhook4_in; - hook_t ifs_ipfhook4_out; - hook_t ifs_ipfhook4_loop_in; - hook_t ifs_ipfhook4_loop_out; - hook_t ifs_ipfhook6_in; - hook_t ifs_ipfhook6_out; - hook_t ifs_ipfhook6_loop_in; - hook_t ifs_ipfhook6_loop_out; - hook_t ifs_ipfhook_nicevents; + hook_t *ifs_ipfhook4_in; + hook_t *ifs_ipfhook4_out; + hook_t *ifs_ipfhook4_loop_in; + hook_t *ifs_ipfhook4_loop_out; + hook_t *ifs_ipfhook4_nicevents; + hook_t *ifs_ipfhook6_in; + hook_t *ifs_ipfhook6_out; + hook_t *ifs_ipfhook6_loop_in; + hook_t *ifs_ipfhook6_loop_out; + hook_t *ifs_ipfhook6_nicevents; /* flags to indicate whether hooks are registered. */ boolean_t ifs_hook4_physical_in; @@ -131,8 +133,8 @@ struct ipf_stack { boolean_t ifs_hook6_loopback_out; int ifs_ipf_loopback; - net_data_t ifs_ipf_ipv4; - net_data_t ifs_ipf_ipv6; + net_handle_t ifs_ipf_ipv4; + net_handle_t ifs_ipf_ipv6; /* ip_auth.c */ int ifs_fr_authsize; diff --git a/usr/src/uts/common/inet/ipf/solaris.c b/usr/src/uts/common/inet/ipf/solaris.c index a48a3250cf..aed5a475a4 100644 --- a/usr/src/uts/common/inet/ipf/solaris.c +++ b/usr/src/uts/common/inet/ipf/solaris.c @@ -3,14 +3,12 @@ * * See the IPFILTER.LICENCE file for details on licencing. * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* #pragma ident "@(#)solaris.c 1.12 6/5/96 (C) 1995 Darren Reed"*/ #pragma ident "@(#)$Id: solaris.c,v 2.73.2.6 2005/07/13 21:40:47 darrenr Exp $" -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/systm.h> #include <sys/types.h> #include <sys/param.h> @@ -39,7 +37,6 @@ #if SOLARIS2 >= 6 # include <net/if_types.h> #endif -#include <sys/netstack.h> #include <net/af.h> #include <net/route.h> #include <netinet/in.h> @@ -71,6 +68,8 @@ static int ipf_identify __P((dev_info_t *)); #endif static int ipf_attach __P((dev_info_t *, ddi_attach_cmd_t)); static int ipf_detach __P((dev_info_t *, ddi_detach_cmd_t)); +static void *ipf_stack_create __P((const netid_t)); +static void ipf_stack_destroy __P((const netid_t, void *)); static int ipf_property_g_update __P((dev_info_t *)); static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, @@ -117,6 +116,10 @@ static struct dev_ops ipf_ops = { (struct bus_ops *)0 }; + +static net_instance_t *ipfncb = NULL; +static ipf_stack_t *ipf_stacks = NULL; +static kmutex_t ipf_stack_lock; extern struct mod_ops mod_driverops; static struct modldrv iplmod = { &mod_driverops, IPL_VERSION, &ipf_ops }; @@ -217,45 +220,51 @@ static const filter_kstats_t ipf_kstat_tmp = { static int ipf_kstat_update(kstat_t *ksp, int rwflag); static void -ipf_kstat_init(ipf_stack_t *ifs, netstackid_t stackid) +ipf_kstat_init(ipf_stack_t *ifs) { - int i; + ifs->ifs_kstatp[0] = net_kstat_create(ifs->ifs_netid, "ipf", 0, + "inbound", "net", KSTAT_TYPE_NAMED, + sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0); + if (ifs->ifs_kstatp[0] != NULL) { + bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[0]->ks_data, + sizeof (filter_kstats_t)); + ifs->ifs_kstatp[0]->ks_update = ipf_kstat_update; + ifs->ifs_kstatp[0]->ks_private = &ifs->ifs_frstats[0]; + kstat_install(ifs->ifs_kstatp[0]); + } - for (i = 0; i < 2; i++) { - ifs->ifs_kstatp[i] = kstat_create_netstack("ipf", 0, - (i==0)?"inbound":"outbound", - "net", - KSTAT_TYPE_NAMED, - sizeof (filter_kstats_t) / sizeof (kstat_named_t), - 0, stackid); - if (ifs->ifs_kstatp[i] != NULL) { - bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[i]->ks_data, - sizeof (filter_kstats_t)); - ifs->ifs_kstatp[i]->ks_update = ipf_kstat_update; - ifs->ifs_kstatp[i]->ks_private = &ifs->ifs_frstats[i]; - kstat_install(ifs->ifs_kstatp[i]); - } + ifs->ifs_kstatp[1] = net_kstat_create(ifs->ifs_netid, "ipf", 0, + "outbound", "net", KSTAT_TYPE_NAMED, + sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0); + if (ifs->ifs_kstatp[1] != NULL) { + bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[1]->ks_data, + sizeof (filter_kstats_t)); + ifs->ifs_kstatp[1]->ks_update = ipf_kstat_update; + ifs->ifs_kstatp[1]->ks_private = &ifs->ifs_frstats[1]; + kstat_install(ifs->ifs_kstatp[1]); } #ifdef IPFDEBUG - cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init() installed 0x%x, 0x%x", - ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]); + cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init(%p) installed %p, %p", + ifs, ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]); #endif } + static void -ipf_kstat_fini(ipf_stack_t *ifs, netstackid_t stackid) +ipf_kstat_fini(ipf_stack_t *ifs) { int i; for (i = 0; i < 2; i++) { if (ifs->ifs_kstatp[i] != NULL) { - kstat_delete_netstack(ifs->ifs_kstatp[i], stackid); + net_kstat_delete(ifs->ifs_netid, ifs->ifs_kstatp[i]); ifs->ifs_kstatp[i] = NULL; } } } + static int ipf_kstat_update(kstat_t *ksp, int rwflag) { @@ -309,6 +318,7 @@ int _init() #ifdef IPFDEBUG cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst); #endif + mutex_init(&ipf_stack_lock, NULL, MUTEX_DRIVER, NULL); return ipfinst; } @@ -332,7 +342,7 @@ struct modinfo *modinfop; ipfinst = mod_info(&modlink1, modinfop); #ifdef IPFDEBUG - cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x", modinfop, ipfinst); + cmn_err(CE_NOTE, "IP Filter: _info(%p) = %d", modinfop, ipfinst); #endif return ipfinst; } @@ -343,7 +353,7 @@ static int ipf_identify(dip) dev_info_t *dip; { # ifdef IPFDEBUG - cmn_err(CE_NOTE, "IP Filter: ipf_identify(%x)", dip); + cmn_err(CE_NOTE, "IP Filter: ipf_identify(%p)", dip); # endif if (strcmp(ddi_get_name(dip), "ipf") == 0) return (DDI_IDENTIFIED); @@ -355,19 +365,17 @@ dev_info_t *dip; * Initialize things for IPF for each stack instance */ static void * -ipf_stack_init(netstackid_t stackid, netstack_t *ns) +ipf_stack_create(const netid_t id) { ipf_stack_t *ifs; -#ifdef NS_DEBUG - (void) printf("ipf_stack_init(%d)\n", stackid); +#ifdef IPFDEBUG + cmn_err(CE_NOTE, "IP Filter:stack_create id=%d", id); #endif - KMALLOCS(ifs, ipf_stack_t *, sizeof (*ifs)); + ifs = (ipf_stack_t *)kmem_alloc(sizeof (*ifs), KM_SLEEP); bzero(ifs, sizeof (*ifs)); - ifs->ifs_netstack = ns; - ifs->ifs_hook4_physical_in = B_FALSE; ifs->ifs_hook4_physical_out = B_FALSE; ifs->ifs_hook4_nic_events = B_FALSE; @@ -384,8 +392,13 @@ ipf_stack_init(netstackid_t stackid, netstack_t *ns) */ RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex"); RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock"); -#ifdef KERNEL - ipf_kstat_init(ifs, stackid); + + ifs->ifs_netid = id; + ifs->ifs_zone = net_getzoneidbynetid(id); + ipf_kstat_init(ifs); + +#ifdef IPFDEBUG + cmn_err(CE_CONT, "IP Filter:stack_create zone=%d", ifs->ifs_zone); #endif /* @@ -396,12 +409,44 @@ ipf_stack_init(netstackid_t stackid, netstack_t *ns) RWLOCK_EXIT(&ifs->ifs_ipf_global); /* Limit to global stack */ - if (stackid == GLOBAL_NETSTACKID) + if (ifs->ifs_zone == GLOBAL_ZONEID) cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version); + mutex_enter(&ipf_stack_lock); + if (ipf_stacks != NULL) + ipf_stacks->ifs_pnext = &ifs->ifs_next; + ifs->ifs_next = ipf_stacks; + ifs->ifs_pnext = &ipf_stacks; + ipf_stacks = ifs; + mutex_exit(&ipf_stack_lock); + return (ifs); } + +/* + * This function should only ever be used to find the pointer to the + * ipfilter stack structure for the zone that is currently being + * executed... so if you're running in the context of zone 1, you + * should not attempt to find the ipf_stack_t for zone 0 or 2 or + * anything else but 1. In that way, the returned pointer is safe + * as it will only be nuked when the instance is destroyed as part + * of the final shutdown of a zone. + */ +ipf_stack_t *ipf_find_stack(const zoneid_t zone) +{ + ipf_stack_t *ifs; + + mutex_enter(&ipf_stack_lock); + for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) { + if (ifs->ifs_zone == zone) + break; + } + mutex_exit(&ipf_stack_lock); + return ifs; +} + + static int ipf_detach_check_zone(ipf_stack_t *ifs) { /* @@ -430,38 +475,32 @@ static int ipf_detach_check_zone(ipf_stack_t *ifs) return (0); } + static int ipf_detach_check_all() { - netstack_handle_t nh; - netstack_t *ns; - int ret; - - netstack_next_init(&nh); - while ((ns = netstack_next(&nh)) != NULL) { - ret = ipf_detach_check_zone(ns->netstack_ipf); - netstack_rele(ns); - if (ret != 0) { - netstack_next_fini(&nh); - return (-1); - } - } + ipf_stack_t *ifs; - netstack_next_fini(&nh); - return (0); + mutex_enter(&ipf_stack_lock); + for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) + if (ipf_detach_check_zone(ifs) != 0) + break; + mutex_exit(&ipf_stack_lock); + return ((ifs == NULL) ? 0 : -1); } + /* * Destroy things for ipf for one stack. */ /* ARGSUSED */ static void -ipf_stack_fini(netstackid_t stackid, void *arg) +ipf_stack_destroy(const netid_t id, void *arg) { ipf_stack_t *ifs = (ipf_stack_t *)arg; + timeout_id_t tid; -#ifdef NS_DEBUG - (void) printf("ipf_stack_destroy(%p, stackid %d)\n", - (void *)ifs, stackid); +#ifdef IPFDEBUG + (void) printf("ipf_stack_destroy(%p)\n", (void *)ifs); #endif /* @@ -474,19 +513,24 @@ ipf_stack_fini(netstackid_t stackid, void *arg) return; } ifs->ifs_fr_running = -2; + tid = ifs->ifs_fr_timer_id; + ifs->ifs_fr_timer_id = NULL; RWLOCK_EXIT(&ifs->ifs_ipf_global); -#ifdef KERNEL - ipf_kstat_fini(ifs, stackid); -#endif - if (ifs->ifs_fr_timer_id != 0) { - (void) untimeout(ifs->ifs_fr_timer_id); - ifs->ifs_fr_timer_id = 0; - } + mutex_enter(&ipf_stack_lock); + if (ifs->ifs_next != NULL) + ifs->ifs_next->ifs_pnext = ifs->ifs_pnext; + *ifs->ifs_pnext = ifs->ifs_next; + mutex_exit(&ipf_stack_lock); + + ipf_kstat_fini(ifs); + + if (tid != NULL) + (void) untimeout(tid); WRITE_ENTER(&ifs->ifs_ipf_global); if (ipldetach(ifs) != 0) { - printf("ipf_stack_fini: ipldetach failed\n"); + printf("ipf_stack_destroy: ipldetach failed\n"); } ipftuneable_free(ifs); @@ -498,6 +542,7 @@ ipf_stack_fini(netstackid_t stackid, void *arg) KFREE(ifs); } + static int ipf_attach(dip, cmd) dev_info_t *dip; ddi_attach_cmd_t cmd; @@ -507,7 +552,7 @@ ddi_attach_cmd_t cmd; int instance; #ifdef IPFDEBUG - cmn_err(CE_NOTE, "IP Filter: ipf_attach(%x,%x)", dip, cmd); + cmn_err(CE_NOTE, "IP Filter: ipf_attach(%p,%x)", dip, cmd); #endif switch (cmd) @@ -519,7 +564,7 @@ ddi_attach_cmd_t cmd; return DDI_FAILURE; #ifdef IPFDEBUG - cmn_err(CE_NOTE, "IP Filter: attach ipf instance %d", instance); + cmn_err(CE_CONT, "IP Filter: attach ipf instance %d", instance); #endif (void) ipf_property_g_update(dip); @@ -538,8 +583,18 @@ ddi_attach_cmd_t cmd; } ipf_dev_info = dip; - netstack_register(NS_IPF, ipf_stack_init, NULL, - ipf_stack_fini); + + ipfncb = net_instance_alloc(NETINFO_VERSION); + ipfncb->nin_name = "ipf"; + ipfncb->nin_create = ipf_stack_create; + ipfncb->nin_destroy = ipf_stack_destroy; + ipfncb->nin_shutdown = NULL; + i = net_instance_register(ipfncb); + +#ifdef IPFDEBUG + cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i); +#endif + return DDI_SUCCESS; /* NOTREACHED */ default: @@ -559,7 +614,7 @@ ddi_detach_cmd_t cmd; int i; #ifdef IPFDEBUG - cmn_err(CE_NOTE, "IP Filter: ipf_detach(%x,%x)", dip, cmd); + cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd); #endif switch (cmd) { case DDI_DETACH: @@ -579,7 +634,9 @@ ddi_detach_cmd_t cmd; return DDI_FAILURE; } - netstack_unregister(NS_IPF); + (void) net_instance_unregister(ipfncb); + net_instance_free(ipfncb); + return DDI_SUCCESS; /* NOTREACHED */ default: @@ -600,7 +657,7 @@ void *arg, **result; error = DDI_FAILURE; #ifdef IPFDEBUG - cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%x,%x,%x)", dip, infocmd, arg); + cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%p,%x,%p)", dip, infocmd, arg); #endif switch (infocmd) { case DDI_INFO_DEVT2DEVINFO: diff --git a/usr/src/uts/common/io/hook.c b/usr/src/uts/common/io/hook.c index 323503498c..8b7129a35b 100644 --- a/usr/src/uts/common/io/hook.c +++ b/usr/src/uts/common/io/hook.c @@ -19,11 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/param.h> #include <sys/types.h> #include <sys/systm.h> @@ -34,6 +32,7 @@ #include <sys/modctl.h> #include <sys/hook_impl.h> #include <sys/sdt.h> +#include <sys/cmn_err.h> /* * This file provides kernel hook framework. @@ -51,6 +50,109 @@ static struct modlinkage modlinkage = { }; /* + * How it works. + * ============= + * Use of the hook framework here is tied up with zones - when a new zone + * is created, we create a new hook_stack_t and are open to business for + * allowing new hook families and their events. + * + * A consumer of these hooks is expected to operate in this fashion: + * 1) call hook_family_add() to create a new family of hooks. It is a + * current requirement that this call must be made with the value + * returned from hook_stack_init, by way of infrastructure elsewhere. + * 2) add events to the registered family with calls to hook_event_add. + * + * At this point, the structures in place should be open to others to + * add hooks to the event or add notifiers for when the contents of the + * hook stack changes. + * + * The interesting stuff happens on teardown. + * + * It is a requirement that the provider of hook events work in the reverse + * order to the above, so that the first step is: + * 1) remove events from each hook family created earlier + * 2) remove hook families from the hook stack. + * + * When doing teardown of both events and families, a check is made to see + * if either structure is still "busy". If so then a boolean flag is set to + * say that the structure is condemned. The presence of this flag being set + * must be checked for in _add()/_register()/ functions and a failure returned + * if it is set. It is ignored by the _find() functions because they're + * used by _remove()/_unregister(). While setting the condemned flag when + * trying to delete a structure would normally be keyed from the presence + * of a reference count being greater than 1, in this implementation there + * are no reference counts required: instead the presence of objects on + * linked lists is taken to mean something is still "busy." + * + * ONLY the caller that adds the family and the events ever has a direct + * reference to the internal structures and thus ONLY it should be doing + * the removal of either the event or family. In practise, what this means + * is that in ip_netinfo.c, we have calls to net_protocol_register(), followed + * by net_event_register() (these interface to hook_family_add() and + * hook_event_add(), respectively) that are made when we create an instance + * of IP and when the IP instance is shutdown/destroyed, it calls + * net_event_unregister() and net_protocol_unregister(), which in turn call + * hook_event_remove() and hook_family_remove() respectively. Nobody else + * is entitled to call the _unregister() functions. It is imperative that + * there be only one _remove() call for every _add() call. + * + * It is possible that code which is interfacing with this hook framework + * won't do all the cleaning up that it needs to at the right time. While + * we can't prevent programmers from creating memory leaks, we can synchronise + * when we clean up data structures to prevent code accessing free'd memory. + * + * A simple diagram showing the ownership is as follows: + * + * Owned +--------------+ + * by | hook_stack_t | + * the +--------------+ + * Instance | + * - - - - - - - -|- - - - - - - - - - - - - - - - - - + * V + * Owned +-------------------+ +-------------------+ + * | hook_family_int_t |---->| hook_family_int_t | + * by +-------------------+ +-------------------+ + * | \+---------------+ \+---------------+ + * network | | hook_family_t | | hook_family_t | + * V +---------------+ +---------------+ + * protocol +------------------+ +------------------+ + * | hook_event_int_t |---->| hook_event_int_t | + * (ipv4,ipv6) +------------------+ +------------------+ + * | \+--------------+ \+--------------+ + * | | hook_event_t | | hook_event_t | + * | +--------------+ +--------------+ + * - - - - - - - -|- - - - - - - - - - - - - - - - - - + * V + * Owned +------------+ + * | hook_int_t | + * by +------------+ + * \+--------+ + * the consumer | hook_t | + * +--------+ + * + * The consumers, such as IPFilter, do not have any pointers or hold any + * references to hook_int_t, hook_event_t or hook_event_int_t. By placing + * a hook on an event through net_hook_register(), an implicit reference + * to the hook_event_int_t is returned with a successful call. Additionally, + * IPFilter does not see the hook_family_int_t or hook_family_t directly. + * Rather it is returned a net_handle_t (from net_protocol_lookup()) that + * contains a pointer to hook_family_int_t. The structure behind the + * net_handle_t (struct net_data) *is* reference counted and managed + * appropriately. + * + * A more detailed picture that describes how the family/event structures + * are linked together can be found in <sys/hook_impl.h> + */ + +/* + * Locking + * ======= + * The use of CVW_* macros to do locking is driven by the need to allow + * recursive locking with read locks when we're processing packets. This + * is necessary because various netinfo functions need to hold read locks, + * by design, as they can be called in or out of packet context. + */ +/* * Hook internal functions */ static hook_int_t *hook_copy(hook_t *src); @@ -58,16 +160,45 @@ 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 void hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi); static hook_family_int_t *hook_family_copy(hook_family_t *src); 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 void hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks); 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_int_free(hook_int_t *hi, netstackid_t); static void hook_init(void); 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); +static void hook_stack_shutdown(netstackid_t stackid, void *arg); +static int hook_insert(hook_int_head_t *head, hook_int_t *new); +static void hook_insert_plain(hook_int_head_t *head, hook_int_t *new); +static int hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new); +static hook_int_t *hook_find_byname(hook_int_head_t *head, char *name); +static void hook_event_init_kstats(hook_family_int_t *, hook_event_int_t *); +static void hook_event_notify_run(hook_event_int_t *, hook_family_int_t *, + char *event, char *name, hook_notify_cmd_t cmd); +static void hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, + hook_int_t *hi); +static int hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head, + hook_notify_fn_t callback, void *arg); +static int hook_notify_unregister(cvwaitlock_t *lock, + hook_notify_head_t *head, hook_notify_fn_t callback); +static void hook_notify_run(hook_notify_head_t *head, char *family, + char *event, char *name, hook_notify_cmd_t cmd); +static void hook_stack_notify_run(hook_stack_t *hks, char *name, + hook_notify_cmd_t cmd); +static void hook_stack_remove(hook_stack_t *hks); + +/* + * A list of the hook stacks is kept here because we need to enable + * net_instance_notify_register() to be called during the creation + * of a new instance. Previously hook_stack_get() would just use + * the netstack functions for this work but they will return NULL + * until the zone has been fully initialised. + */ +static hook_stack_head_t hook_stacks; +static kmutex_t hook_stack_lock; /* * Module entry points. @@ -85,7 +216,6 @@ _init(void) return (error); } - int _fini(void) { @@ -98,14 +228,12 @@ _fini(void) return (error); } - int _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } - /* * Function: hook_init * Returns: None @@ -116,11 +244,14 @@ _info(struct modinfo *modinfop) static void hook_init(void) { + mutex_init(&hook_stack_lock, NULL, MUTEX_DRIVER, NULL); + SLIST_INIT(&hook_stacks); + /* * We want to be informed each time a stack is created or * destroyed in the kernel. */ - netstack_register(NS_HOOK, hook_stack_init, NULL, + netstack_register(NS_HOOK, hook_stack_init, hook_stack_shutdown, hook_stack_fini); } @@ -135,6 +266,134 @@ static void hook_fini(void) { netstack_unregister(NS_HOOK); + + mutex_destroy(&hook_stack_lock); + ASSERT(SLIST_EMPTY(&hook_stacks)); +} + +/* + * Function: hook_wait_setflag + * Returns: -1 = setting flag is disallowed, 0 = flag set and did + * not have to wait (ie no lock droped), 1 = flag set but + * it was necessary to drop locks to set it. + * Parameters: waiter(I) - control data structure + * busyset(I) - set of flags that we don't want set while + * we are active. + * wanted(I) - flag associated with newflag to indicate + * what we want to do. + * newflag(I) - the new ACTIVE flag we want to set that + * indicates what we are doing. + * + * The set of functions hook_wait_* implement an API that builds on top of + * the kcondvar_t to provide controlled execution through a critical region. + * For each flag that indicates work is being done (FWF_*_ACTIVE) there is + * also a flag that we set to indicate that we want to do it (FWF_*_WANTED). + * The combination of flags is required as when this function exits to do + * the task, the structure is then free for another caller to use and + * to indicate that it wants to do work. The trump flags here are those + * that indicate someone wants to destroy the structure that owns this + * flagwait_t. In this case, we don't try to secure the ability to run + * and return with an error. + * + * wanted - the FWF_*_WANTED flag that describes the action being requested + * busyset- the set of FWF_* flags we don't want set when we run + * newflag- the FWF_*_ACTIVE flag we will set to indicate we are busy + */ +int +hook_wait_setflag(flagwait_t *waiter, uint32_t busyset, fwflag_t wanted, + fwflag_t newflag) +{ + int waited = 0; + + mutex_enter(&waiter->fw_lock); + if (waiter->fw_flags & FWF_DESTROY) { + mutex_exit(&waiter->fw_lock); + return (-1); + } + while (waiter->fw_flags & busyset) { + waiter->fw_flags |= wanted; + CVW_EXIT_WRITE(waiter->fw_owner); + cv_wait(&waiter->fw_cv, &waiter->fw_lock); + waited = 1; + CVW_ENTER_WRITE(waiter->fw_owner); + if (waiter->fw_flags & FWF_DESTROY) { + waiter->fw_flags &= ~wanted; + mutex_exit(&waiter->fw_lock); + return (-1); + } + waiter->fw_flags |= wanted; + } + waiter->fw_flags &= ~wanted; + waiter->fw_flags |= newflag; + mutex_exit(&waiter->fw_lock); + return (waited); +} + +/* + * Function: hook_wait_unsetflag + * Returns: None + * Parameters: waiter(I) - control data structure + * oldflag(I) - flag to reset + * + * Turn off the bit that we had set to run and let others know that + * they should now check to see if they can run. + */ +void +hook_wait_unsetflag(flagwait_t *waiter, uint32_t oldflag) +{ + mutex_enter(&waiter->fw_lock); + waiter->fw_flags &= ~oldflag; + cv_signal(&waiter->fw_cv); + mutex_exit(&waiter->fw_lock); +} + +/* + * Function: hook_wait_destroy + * Returns: None + * Parameters: waiter(I) - control data structure + * + * Since outer locking (on fw_owner) should ensure that only one function + * at a time gets to call hook_wait_destroy() on a given object, there is + * no need to guard against setting FWF_DESTROY_WANTED already being set. + * It is, however, necessary to wait for all activity on the owning + * structure to cease. + */ +void +hook_wait_destroy(flagwait_t *waiter) +{ + ASSERT((waiter->fw_flags & FWF_DESTROY_WANTED) == 0); + waiter->fw_flags |= FWF_DESTROY_WANTED; + while (!FWF_DESTROY_OK(waiter)) { + CVW_EXIT_WRITE(waiter->fw_owner); + cv_wait(&waiter->fw_cv, &waiter->fw_lock); + CVW_ENTER_WRITE(waiter->fw_owner); + } + /* + * There should now be nothing else using "waiter" or its + * owner, so we can safely assign here without risk of wiiping + * out someone's bit. + */ + waiter->fw_flags = FWF_DESTROY_ACTIVE; +} + +/* + * Function: hook_wait_init + * Returns: None + * Parameters: waiter(I) - control data structure + * ownder(I) - pointer to lock that the owner of this + * waiter uses + * + * "owner" gets passed in here so that when we need to call cv_wait, + * for example in hook_wait_setflag(), we can drop the lock for the + * next layer out, which is likely to be held in an exclusive manner. + */ +void +hook_wait_init(flagwait_t *waiter, cvwaitlock_t *owner) +{ + cv_init(&waiter->fw_cv, NULL, CV_DRIVER, NULL); + mutex_init(&waiter->fw_lock, NULL, MUTEX_DRIVER, NULL); + waiter->fw_flags = FWF_NONE; + waiter->fw_owner = owner; } /* @@ -151,14 +410,37 @@ hook_stack_init(netstackid_t stackid, netstack_t *ns) #endif hks = (hook_stack_t *)kmem_zalloc(sizeof (*hks), KM_SLEEP); - hks->hk_netstack = ns; + hks->hks_netstack = ns; + hks->hks_netstackid = stackid; - CVW_INIT(&hks->hks_familylock); + CVW_INIT(&hks->hks_lock); + TAILQ_INIT(&hks->hks_nhead); SLIST_INIT(&hks->hks_familylist); + hook_wait_init(&hks->hks_waiter, &hks->hks_lock); + + mutex_enter(&hook_stack_lock); + SLIST_INSERT_HEAD(&hook_stacks, hks, hks_entry); + mutex_exit(&hook_stack_lock); + return (hks); } +/*ARGSUSED*/ +static void +hook_stack_shutdown(netstackid_t stackid, void *arg) +{ + hook_stack_t *hks = (hook_stack_t *)arg; + + mutex_enter(&hook_stack_lock); + /* + * Once this flag gets set to one, no more additions are allowed + * to any of the structures that make up this stack. + */ + hks->hks_shutdown = 1; + mutex_exit(&hook_stack_lock); +} + /* * Free the hook stack instance. */ @@ -166,14 +448,143 @@ hook_stack_init(netstackid_t stackid, netstack_t *ns) 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); + hook_stack_t *hks = (hook_stack_t *)arg; + + mutex_enter(&hook_stack_lock); + hks->hks_shutdown = 2; + hook_stack_remove(hks); + mutex_exit(&hook_stack_lock); +} + +/* + * This function assumes that it is called with hook_stack_lock held. + * It functions differently to hook_family/event_remove in that it does + * the checks to see if it can be removed. This difference exists + * because this structure has nothing higher up that depends on it. + */ +static void +hook_stack_remove(hook_stack_t *hks) +{ + + ASSERT(mutex_owned(&hook_stack_lock)); + + /* + * Is the structure still in use? + */ + if (!SLIST_EMPTY(&hks->hks_familylist) || + !TAILQ_EMPTY(&hks->hks_nhead)) + return; + + SLIST_REMOVE(&hook_stacks, hks, hook_stack, hks_entry); + + hook_wait_destroy(&hks->hks_waiter); + CVW_DESTROY(&hks->hks_lock); kmem_free(hks, sizeof (*hks)); } +static hook_stack_t * +hook_stack_get(netstackid_t stackid) +{ + hook_stack_t *hks; + + SLIST_FOREACH(hks, &hook_stacks, hks_entry) { + if (hks->hks_netstackid == stackid) + break; + } + + return (hks); +} + +/* + * Function: hook_stack_notify_register + * Returns: 0 = success, else failure + * Parameters: stackid(I) - netstack identifier + * callback(I)- function to be called + * arg(I) - arg to provide callback when it is called + * + * If we're not shutting down this instance, append a new function to the + * list of those to call when a new family of hooks is added to this stack. + */ +int +hook_stack_notify_register(netstackid_t stackid, hook_notify_fn_t callback, + void *arg) +{ + hook_stack_t *hks; + int error; + + mutex_enter(&hook_stack_lock); + hks = hook_stack_get(stackid); + if (hks != NULL) { + if (hks->hks_shutdown != 0) { + error = ESHUTDOWN; + } else { + error = hook_notify_register(&hks->hks_lock, + &hks->hks_nhead, callback, arg); + } + } else { + error = ESRCH; + } + mutex_exit(&hook_stack_lock); + + return (error); +} + +/* + * Function: hook_stack_notify_unregister + * Returns: 0 = success, else failure + * Parameters: stackid(I) - netstack identifier + * callback(I) - function to be called + * + * Attempt to remove a registered function from a hook stack's list of + * callbacks to activiate when protocols are added/deleted. + */ +int +hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback) +{ + hook_stack_t *hks; + int error; + + mutex_enter(&hook_stack_lock); + hks = hook_stack_get(stackid); + if (hks != NULL) { + error = hook_notify_unregister(&hks->hks_lock, + &hks->hks_nhead, callback); + if ((error == 0) && (hks->hks_shutdown == 2)) + hook_stack_remove(hks); + } else { + error = ESRCH; + } + mutex_exit(&hook_stack_lock); + + return (error); +} + +/* + * Function: hook_stack_notify_run + * Returns: None + * Parameters: hks(I) - hook stack pointer to execute callbacks for + * name(I) - name of a hook family + * cmd(I) - either HN_UNREGISTER or HN_REGISTER + * + * Run through the list of callbacks on the hook stack to be called when + * a new hook family is added + * + * As hook_notify_run() expects 3 names, one for the family, one for the + * event and one for the object being introduced and we really only have + * one name (that of the new hook family), fake the hook stack's name by + * converting the integer to a string and for the event just pass NULL. + */ +static void +hook_stack_notify_run(hook_stack_t *hks, char *name, + hook_notify_cmd_t cmd) +{ + char buffer[16]; + + (void) snprintf(buffer, sizeof (buffer), "%u", hks->hks_netstackid); + + hook_notify_run(&hks->hks_nhead, buffer, NULL, name, cmd); +} + /* * Function: hook_run * Returns: int - return value according to callback func @@ -187,11 +598,10 @@ hook_stack_fini(netstackid_t stackid, void *arg) * called more than once, simultaneously. */ int -hook_run(hook_event_token_t token, hook_data_t info, netstack_t *ns) +hook_run(hook_family_int_t *hfi, hook_event_token_t token, hook_data_t info) { - hook_int_t *hi; hook_event_int_t *hei; - hook_stack_t *hks = ns->netstack_hook; + hook_int_t *hi; int rval = 0; ASSERT(token != NULL); @@ -201,11 +611,17 @@ hook_run(hook_event_token_t token, hook_data_t info, netstack_t *ns) hook_event_token_t, token, hook_data_t, info); - /* Hold global read lock to ensure event will not be deleted */ - CVW_ENTER_READ(&hks->hks_familylock); - - /* Hold event read lock to ensure hook will not be changed */ - CVW_ENTER_READ(&hei->hei_lock); + /* + * Hold global read lock to ensure event will not be deleted. + * While it might be expected that we should also hold a read lock + * on the event lock (hei_lock) to prevent the hook list from + * changing while we're executing this function, both addition + * to and removal from the hook list on the event is done with + * a write lock held on hfi_lock. This is by design so that we + * only need to get one of these locks to process a packet. + * - locking is not a cheap thing to do for every packet. + */ + CVW_ENTER_READ(&hfi->hfi_lock); TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) { ASSERT(hi->hi_hook.h_func != NULL); @@ -213,18 +629,20 @@ hook_run(hook_event_token_t token, hook_data_t info, netstack_t *ns) hook_event_token_t, token, hook_data_t, info, hook_int_t *, hi); - rval = (*hi->hi_hook.h_func)(token, info, ns); + rval = (*hi->hi_hook.h_func)(token, info, hi->hi_hook.h_arg); DTRACE_PROBE4(hook__func__end, hook_event_token_t, token, hook_data_t, info, hook_int_t *, hi, int, rval); + hi->hi_kstats.hook_hits.value.ui64++; if (rval != 0) break; } - CVW_EXIT_READ(&hei->hei_lock); - CVW_EXIT_READ(&hks->hks_familylock); + hei->hei_kstats.events.value.ui64++; + + CVW_EXIT_READ(&hfi->hfi_lock); DTRACE_PROBE3(hook__run__end, hook_event_token_t, token, @@ -234,7 +652,6 @@ hook_run(hook_event_token_t token, hook_data_t info, netstack_t *ns) return (rval); } - /* * Function: hook_family_add * Returns: internal family pointer - NULL = Fail @@ -254,32 +671,62 @@ hook_family_add(hook_family_t *hf, hook_stack_t *hks) if (new == NULL) return (NULL); - CVW_ENTER_WRITE(&hks->hks_familylock); + mutex_enter(&hook_stack_lock); + CVW_ENTER_WRITE(&hks->hks_lock); + + if (hks->hks_shutdown != 0) { + CVW_EXIT_WRITE(&hks->hks_lock); + mutex_exit(&hook_stack_lock); + hook_family_free(new, NULL); + return (NULL); + } /* search family list */ hfi = hook_family_find(hf->hf_name, hks); if (hfi != NULL) { - CVW_EXIT_WRITE(&hks->hks_familylock); - hook_family_free(new); + CVW_EXIT_WRITE(&hks->hks_lock); + mutex_exit(&hook_stack_lock); + hook_family_free(new, NULL); return (NULL); } - new->hfi_ptr = (void *)hks; + if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK, + FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { + CVW_EXIT_WRITE(&hks->hks_lock); + mutex_exit(&hook_stack_lock); + hook_family_free(new, NULL); + return (NULL); + } + + CVW_INIT(&new->hfi_lock); + SLIST_INIT(&new->hfi_head); + TAILQ_INIT(&new->hfi_nhead); + + hook_wait_init(&new->hfi_waiter, &new->hfi_lock); + + new->hfi_stack = hks; /* Add to family list head */ SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry); - CVW_EXIT_WRITE(&hks->hks_familylock); + CVW_EXIT_WRITE(&hks->hks_lock); + mutex_exit(&hook_stack_lock); + + hook_stack_notify_run(hks, hf->hf_name, HN_REGISTER); + + hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE); + return (new); } - /* * Function: hook_family_remove * Returns: int - 0 = Succ, Else = Fail * Parameters: hfi(I) - internal family pointer * - * Remove family from family list + * Remove family from family list. This function has been designed to be + * called once and once only per hook_family_int_t. Thus when cleaning up + * this structure as an orphan, callers should only call hook_family_free. */ int hook_family_remove(hook_family_int_t *hfi) @@ -287,27 +734,99 @@ hook_family_remove(hook_family_int_t *hfi) hook_stack_t *hks; ASSERT(hfi != NULL); - hks = (hook_stack_t *)hfi->hfi_ptr; + hks = hfi->hfi_stack; - CVW_ENTER_WRITE(&hks->hks_familylock); + CVW_ENTER_WRITE(&hks->hks_lock); + + if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK, + FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { + /* + * If we're trying to destroy the hook_stack_t... + */ + return (ENXIO); + } - /* Check if there are events */ - if (!SLIST_EMPTY(&hfi->hfi_head)) { - CVW_EXIT_WRITE(&hks->hks_familylock); - return (EBUSY); + /* + * Check if the family is in use by the presence of either events + * or notify callbacks on the hook family. + */ + if (!SLIST_EMPTY(&hfi->hfi_head) || !TAILQ_EMPTY(&hfi->hfi_nhead)) { + hfi->hfi_condemned = B_TRUE; + } else { + /* + * Although hfi_condemned = B_FALSE is implied from creation, + * putting a comment here inside the else upsets lint. + */ + hfi->hfi_condemned = B_FALSE; } - /* Remove from family list */ - SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int, hfi_entry); + CVW_ENTER_WRITE(&hfi->hfi_lock); + hook_wait_destroy(&hfi->hfi_waiter); + CVW_EXIT_WRITE(&hfi->hfi_lock); + + CVW_EXIT_WRITE(&hks->hks_lock); + + hook_stack_notify_run(hks, hfi->hfi_family.hf_name, HN_UNREGISTER); - CVW_EXIT_WRITE(&hks->hks_familylock); - hook_family_free(hfi); + hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE); + + /* + * If we don't have to wait for anything else to disappear from this + * structure then we can free it up. + */ + if (!hfi->hfi_condemned) + hook_family_free(hfi, hks); return (0); } /* + * Function: hook_family_free + * Returns: None + * Parameters: hfi(I) - internal family pointer + * + * Free alloc memory for family + */ +static void +hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks) +{ + + /* + * This lock gives us possession of the hks pointer after the + * SLIST_REMOVE, for which it is not needed, when hks_shutdown + * is checked and hook_stack_remove called. + */ + mutex_enter(&hook_stack_lock); + + ASSERT(hfi != NULL); + + if (hks != NULL) { + CVW_ENTER_WRITE(&hks->hks_lock); + /* Remove from family list */ + SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int, + hfi_entry); + + CVW_EXIT_WRITE(&hks->hks_lock); + } + + /* Free name space */ + if (hfi->hfi_family.hf_name != NULL) { + kmem_free(hfi->hfi_family.hf_name, + strlen(hfi->hfi_family.hf_name) + 1); + } + + /* Free container */ + kmem_free(hfi, sizeof (*hfi)); + + if (hks->hks_shutdown == 2) + hook_stack_remove(hks); + + mutex_exit(&hook_stack_lock); +} + + +/* * Function: hook_family_copy * Returns: internal family pointer - NULL = Failed * Parameters: src(I) - family pointer @@ -327,10 +846,12 @@ hook_family_copy(hook_family_t *src) new = (hook_family_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); /* Copy body */ - SLIST_INIT(&new->hfi_head); dst = &new->hfi_family; *dst = *src; + SLIST_INIT(&new->hfi_head); + TAILQ_INIT(&new->hfi_nhead); + /* Copy name */ dst->hf_name = (char *)kmem_alloc(strlen(src->hf_name) + 1, KM_SLEEP); (void) strcpy(dst->hf_name, src->hf_name); @@ -338,13 +859,13 @@ hook_family_copy(hook_family_t *src) return (new); } - /* + * Function: hook_family_find * Returns: internal family pointer - NULL = Not match * Parameters: family(I) - family name string * * Search family list with family name - * A lock on familylock must be held when called. + * A lock on hfi_lock must be held when called. */ static hook_family_int_t * hook_family_find(char *family, hook_stack_t *hks) @@ -360,29 +881,90 @@ hook_family_find(char *family, hook_stack_t *hks) return (hfi); } - /* - * Function: hook_family_free - * Returns: None - * Parameters: hfi(I) - internal family pointer + * Function: hook_family_notify_register + * Returns: 0 = success, else failure + * Parameters: hfi(I) - hook family + * callback(I) - function to be called + * arg(I) - arg to provide callback when it is called * - * Free alloc memory for family + * So long as this hook stack isn't being shut down, register a new + * callback to be activated each time a new event is added to this + * family. + * + * To call this function we must have an active handle in use on the family, + * so if we take this into account, then neither the hook_family_int_t nor + * the hook_stack_t that owns it can disappear. We have to put some trust + * in the callers to be properly synchronised... + * + * Holding hks_lock is required to provide synchronisation for hks_shutdown. */ -static void -hook_family_free(hook_family_int_t *hfi) +int +hook_family_notify_register(hook_family_int_t *hfi, + hook_notify_fn_t callback, void *arg) { - ASSERT(hfi != NULL); + hook_stack_t *hks; + int error; - /* Free name space */ - if (hfi->hfi_family.hf_name != NULL) { - kmem_free(hfi->hfi_family.hf_name, - strlen(hfi->hfi_family.hf_name) + 1); + hks = hfi->hfi_stack; + + CVW_ENTER_READ(&hks->hks_lock); + CVW_ENTER_WRITE(&hfi->hfi_lock); + + if (hfi->hfi_stack->hks_shutdown != 0) { + CVW_EXIT_WRITE(&hfi->hfi_lock); + CVW_EXIT_READ(&hks->hks_lock); + return (ESHUTDOWN); } - /* Free container */ - kmem_free(hfi, sizeof (*hfi)); + error = hook_notify_register(&hfi->hfi_lock, &hfi->hfi_nhead, + callback, arg); + + CVW_EXIT_WRITE(&hfi->hfi_lock); + CVW_EXIT_READ(&hks->hks_lock); + + return (error); } +/* + * Function: hook_family_notify_unregister + * Returns: 0 = success, else failure + * Parameters: hfi(I) - hook family + * callback(I) - function to be called + * + * Remove a callback from the list of those executed when a new event is + * added to a hook family. + */ +int +hook_family_notify_unregister(hook_family_int_t *hfi, + hook_notify_fn_t callback) +{ + boolean_t free_family; + int error; + + CVW_ENTER_WRITE(&hfi->hfi_lock); + + error = hook_notify_unregister(&hfi->hfi_lock, &hfi->hfi_nhead, + callback); + + /* + * If hook_family_remove has been called but the structure was still + * "busy" ... but we might have just made it "unbusy"... + */ + if ((error == 0) && hfi->hfi_condemned && + SLIST_EMPTY(&hfi->hfi_head) && TAILQ_EMPTY(&hfi->hfi_nhead)) { + free_family = B_TRUE; + } else { + free_family = B_FALSE; + } + + CVW_EXIT_WRITE(&hfi->hfi_lock); + + if (free_family) + hook_family_free(hfi, hfi->hfi_stack); + + return (error); +} /* * Function: hook_event_add @@ -398,35 +980,110 @@ 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; + hook_stack_t *hks; 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(&hks->hks_familylock); + hks = hfi->hfi_stack; + CVW_ENTER_READ(&hks->hks_lock); + + hks = hfi->hfi_stack; + if (hks->hks_shutdown != 0) { + CVW_EXIT_READ(&hks->hks_lock); + hook_event_free(new, NULL); + return (NULL); + } /* Check whether this event pointer is already registered */ hei = hook_event_checkdup(he, hks); if (hei != NULL) { - CVW_EXIT_WRITE(&hks->hks_familylock); - hook_event_free(new); + CVW_EXIT_READ(&hks->hks_lock); + hook_event_free(new, NULL); return (NULL); } + CVW_ENTER_WRITE(&hfi->hfi_lock); + + if (hfi->hfi_condemned) { + CVW_EXIT_WRITE(&hfi->hfi_lock); + CVW_EXIT_READ(&hks->hks_lock); + hook_event_free(new, NULL); + return (NULL); + } + + if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK, + FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { + CVW_EXIT_WRITE(&hfi->hfi_lock); + CVW_EXIT_READ(&hks->hks_lock); + hook_event_free(new, NULL); + return (NULL); + } + + TAILQ_INIT(&new->hei_nhead); + + hook_event_init_kstats(hfi, new); + hook_wait_init(&new->hei_waiter, &new->hei_lock); + /* Add to event list head */ SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry); - CVW_EXIT_WRITE(&hks->hks_familylock); + CVW_EXIT_WRITE(&hfi->hfi_lock); + + CVW_EXIT_READ(&hks->hks_lock); + + hook_notify_run(&hfi->hfi_nhead, + hfi->hfi_family.hf_name, NULL, he->he_name, HN_REGISTER); + + hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE); + return (new); } +/* + * Function: hook_event_init_kstats + * Returns: None + * Parameters: hfi(I) - pointer to the family that owns this event. + * hei(I) - pointer to the hook event that needs some kstats. + * + * Create a set of kstats that relate to each event registered with + * the hook framework. A counter is kept for each time the event is + * activated and for each time a hook is added or removed. As the + * kstats just count the events as they happen, the total number of + * hooks registered must be obtained by subtractived removed from added. + */ +static void +hook_event_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei) +{ + hook_event_kstat_t template = { + { "hooksAdded", KSTAT_DATA_UINT64 }, + { "hooksRemoved", KSTAT_DATA_UINT64 }, + { "events", KSTAT_DATA_UINT64 } + }; + hook_stack_t *hks; + + hks = hfi->hfi_stack; + hei->hei_kstatp = kstat_create_netstack(hfi->hfi_family.hf_name, 0, + hei->hei_event->he_name, "hook_event", KSTAT_TYPE_NAMED, + sizeof (hei->hei_kstats) / sizeof (kstat_named_t), + KSTAT_FLAG_VIRTUAL, hks->hks_netstackid); + + bcopy((char *)&template, &hei->hei_kstats, sizeof (template)); + + if (hei->hei_kstatp != NULL) { + hei->hei_kstatp->ks_data = (void *)&hei->hei_kstats; + hei->hei_kstatp->ks_private = + (void *)(uintptr_t)hks->hks_netstackid; + + kstat_install(hei->hei_kstatp); + } +} /* * Function: hook_event_remove @@ -435,48 +1092,136 @@ hook_event_add(hook_family_int_t *hfi, hook_event_t *he) * he(I) - event pointer * * Remove event from event list on specific family + * + * This function assumes that the caller has received a pointer to a the + * hook_family_int_t via a call to net_protocol_lookup or net_protocol_unreg'. + * This the hook_family_int_t is guaranteed to be around for the life of this + * call, unless the caller has decided to call net_protocol_release or + * net_protocol_unregister before calling net_event_unregister - an error. */ int hook_event_remove(hook_family_int_t *hfi, hook_event_t *he) { - hook_stack_t *hks; + boolean_t free_family; hook_event_int_t *hei; ASSERT(hfi != NULL); ASSERT(he != NULL); - hks = (hook_stack_t *)hfi->hfi_ptr; - CVW_ENTER_WRITE(&hks->hks_familylock); + CVW_ENTER_WRITE(&hfi->hfi_lock); + + /* + * Set the flag so that we can call hook_event_notify_run without + * holding any locks but at the same time prevent other changes to + * the event at the same time. + */ + if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK, + FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { + CVW_EXIT_WRITE(&hfi->hfi_lock); + return (ENXIO); + } hei = hook_event_find(hfi, he->he_name); if (hei == NULL) { - CVW_EXIT_WRITE(&hks->hks_familylock); - return (ENXIO); + hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE); + CVW_EXIT_WRITE(&hfi->hfi_lock); + return (ESRCH); } - /* Check if there are registered hooks for this event */ - if (!TAILQ_EMPTY(&hei->hei_head)) { - CVW_EXIT_WRITE(&hks->hks_familylock); - return (EBUSY); + free_family = B_FALSE; + + CVW_ENTER_WRITE(&hei->hei_lock); + /* + * If there are any hooks still registered for this event or + * there are any notifiers registered, return an error indicating + * that the event is still busy. + */ + if (!TAILQ_EMPTY(&hei->hei_head) || !TAILQ_EMPTY(&hei->hei_nhead)) { + hei->hei_condemned = B_TRUE; + CVW_EXIT_WRITE(&hei->hei_lock); + } else { + /* hei_condemned = B_FALSE is implied from creation */ + /* + * Even though we know the notify list is empty, we call + * hook_wait_destroy here to synchronise wait removing a + * hook from an event. + */ + hook_wait_destroy(&hei->hei_waiter); + + CVW_EXIT_WRITE(&hei->hei_lock); + + if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) && + TAILQ_EMPTY(&hfi->hfi_nhead)) + free_family = B_TRUE; } - /* Remove from event list */ - SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry); + CVW_EXIT_WRITE(&hfi->hfi_lock); + + hook_notify_run(&hfi->hfi_nhead, + hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER); - CVW_EXIT_WRITE(&hks->hks_familylock); - hook_event_free(hei); + hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE); + + if (!hei->hei_condemned) { + hook_event_free(hei, hfi); + if (free_family) + hook_family_free(hfi, hfi->hfi_stack); + } return (0); } +/* + * Function: hook_event_free + * Returns: None + * Parameters: hei(I) - internal event pointer + * + * Free alloc memory for event + */ +static void +hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi) +{ + boolean_t free_family; + + ASSERT(hei != NULL); + + if (hfi != NULL) { + CVW_ENTER_WRITE(&hfi->hfi_lock); + /* + * Remove the event from the hook family's list. + */ + SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry); + if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) && + TAILQ_EMPTY(&hfi->hfi_nhead)) { + free_family = B_TRUE; + } else { + free_family = B_FALSE; + } + CVW_EXIT_WRITE(&hfi->hfi_lock); + } + + if (hei->hei_kstatp != NULL) { + ASSERT(hfi != NULL); + + kstat_delete_netstack(hei->hei_kstatp, + hfi->hfi_stack->hks_netstackid); + hei->hei_kstatp = NULL; + } + + /* Free container */ + kmem_free(hei, sizeof (*hei)); + + if (free_family) + hook_family_free(hfi, hfi->hfi_stack); +} /* * Function: hook_event_checkdup * Returns: internal event pointer - NULL = Not match * Parameters: he(I) - event pointer * - * Search whole list with event pointer - * A lock on familylock must be held when called. + * Search all of the hook families to see if the event being passed in + * has already been associated with one. */ static hook_event_int_t * hook_event_checkdup(hook_event_t *he, hook_stack_t *hks) @@ -486,17 +1231,20 @@ hook_event_checkdup(hook_event_t *he, hook_stack_t *hks) ASSERT(he != NULL); + CVW_ENTER_READ(&hks->hks_lock); SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { - if (hei->hei_event == he) + if (hei->hei_event == he) { + CVW_EXIT_READ(&hks->hks_lock); return (hei); + } } } + CVW_EXIT_READ(&hks->hks_lock); return (NULL); } - /* * Function: hook_event_copy * Returns: internal event pointer - NULL = Failed @@ -522,7 +1270,6 @@ hook_event_copy(hook_event_t *src) return (new); } - /* * Function: hook_event_find * Returns: internal event pointer - NULL = Not match @@ -530,7 +1277,7 @@ hook_event_copy(hook_event_t *src) * event(I) - event name string * * Search event list with event name - * A lock on hks->hks_familylock must be held when called. + * A lock on hfi->hfi_lock must be held when called. */ static hook_event_int_t * hook_event_find(hook_family_int_t *hfi, char *event) @@ -541,30 +1288,157 @@ hook_event_find(hook_family_int_t *hfi, char *event) ASSERT(event != NULL); SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { - if (strcmp(hei->hei_event->he_name, event) == 0) + if ((strcmp(hei->hei_event->he_name, event) == 0) && + ((hei->hei_waiter.fw_flags & FWF_UNSAFE) == 0)) break; } return (hei); } +/* + * Function: hook_event_notify_register + * Returns: 0 = success, else failure + * Parameters: hfi(I) - hook family + * event(I) - name of the event + * callback(I) - function to be called + * arg(I) - arg to provide callback when it is called + * + * Adds a new callback to the event named by "event" (we must find it) + * that will be executed each time a new hook is added to the event. + * Of course, if the stack is being shut down, this call should fail. + */ +int +hook_event_notify_register(hook_family_int_t *hfi, char *event, + hook_notify_fn_t callback, void *arg) +{ + hook_event_int_t *hei; + hook_stack_t *hks; + int error; + + hks = hfi->hfi_stack; + CVW_ENTER_READ(&hks->hks_lock); + if (hks->hks_shutdown != 0) { + CVW_EXIT_READ(&hks->hks_lock); + return (ESHUTDOWN); + } + + CVW_ENTER_READ(&hfi->hfi_lock); + + if (hfi->hfi_condemned) { + CVW_EXIT_READ(&hfi->hfi_lock); + CVW_EXIT_READ(&hks->hks_lock); + return (ESHUTDOWN); + } + + hei = hook_event_find(hfi, event); + if (hei == NULL) { + CVW_EXIT_READ(&hfi->hfi_lock); + CVW_EXIT_READ(&hks->hks_lock); + return (ESRCH); + } + + /* + * Grabbing the read lock on hei_lock is only so that we can + * synchronise access to hei_condemned. + */ + CVW_ENTER_WRITE(&hei->hei_lock); + if (hei->hei_condemned) { + CVW_EXIT_WRITE(&hei->hei_lock); + CVW_EXIT_READ(&hfi->hfi_lock); + CVW_EXIT_READ(&hks->hks_lock); + return (ESHUTDOWN); + } + + error = hook_notify_register(&hei->hei_lock, &hei->hei_nhead, + callback, arg); + + CVW_EXIT_WRITE(&hei->hei_lock); + CVW_EXIT_READ(&hfi->hfi_lock); + CVW_EXIT_READ(&hks->hks_lock); + + return (error); +} /* - * Function: hook_event_free + * Function: hook_event_notify_unregister + * Returns: 0 = success, else failure + * Parameters: hfi(I) - hook family + * event(I) - name of the event + * callback(I) - function to be called + * + * Remove the given callback from the named event's list of functions + * to call when a hook is added or removed. + */ +int +hook_event_notify_unregister(hook_family_int_t *hfi, char *event, + hook_notify_fn_t callback) +{ + hook_event_int_t *hei; + boolean_t free_event; + int error; + + CVW_ENTER_READ(&hfi->hfi_lock); + + hei = hook_event_find(hfi, event); + if (hei == NULL) { + CVW_EXIT_READ(&hfi->hfi_lock); + return (ESRCH); + } + + CVW_ENTER_WRITE(&hei->hei_lock); + + error = hook_notify_unregister(&hei->hei_lock, &hei->hei_nhead, + callback); + + /* + * hei_condemned has been set if someone tried to remove the + * event but couldn't because there were still things attached to + * it. Now that we've done a successful remove, if it is now empty + * then by all rights we should be free'ing it too. Note that the + * expectation is that only the caller of hook_event_add will ever + * call hook_event_remove. + */ + if ((error == 0) && hei->hei_condemned && + TAILQ_EMPTY(&hei->hei_head) && TAILQ_EMPTY(&hei->hei_nhead)) { + free_event = B_TRUE; + } else { + free_event = B_FALSE; + } + + CVW_EXIT_WRITE(&hei->hei_lock); + CVW_EXIT_READ(&hfi->hfi_lock); + + if (free_event) { + /* + * It is safe to pass in hfi here, without a lock, because + * our structure (hei) is still on one of its lists and thus + * it won't be able to disappear yet... + */ + hook_event_free(hei, hfi); + } + + return (error); +} + +/* + * Function: hook_event_notify_run * Returns: None - * Parameters: hei(I) - internal event pointer + * Parameters: nrun(I) - pointer to the list of callbacks to execute + * hfi(I) - hook stack pointer to execute callbacks for + * name(I) - name of a hook family + * cmd(I) - either HN_UNREGISTER or HN_REGISTER * - * Free alloc memory for event + * Execute all of the callbacks registered for this event. */ static void -hook_event_free(hook_event_int_t *hei) +hook_event_notify_run(hook_event_int_t *hei, hook_family_int_t *hfi, + char *event, char *name, hook_notify_cmd_t cmd) { - ASSERT(hei != NULL); - /* Free container */ - kmem_free(hei, sizeof (*hei)); + hook_notify_run(&hei->hei_nhead, hfi->hfi_family.hf_name, + event, name, cmd); } - /* * Function: hook_register * Returns: int- 0 = Succ, Else = Fail @@ -572,19 +1446,21 @@ hook_event_free(hook_event_int_t *hei) * event(I) - event name string * h(I) - hook pointer * - * Add new hook to hook list on spefic family, event + * Add new hook to hook list on the specified family and event. */ 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; + int error; ASSERT(hfi != NULL); ASSERT(event != NULL); ASSERT(h != NULL); - hks = (hook_stack_t *)hfi->hfi_ptr; + + if (hfi->hfi_stack->hks_shutdown) + return (NULL); /* Alloc hook_int_t and copy hook */ new = hook_copy(h); @@ -596,43 +1472,255 @@ 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(&hks->hks_familylock); + CVW_ENTER_WRITE(&hfi->hfi_lock); hei = hook_event_find(hfi, event); if (hei == NULL) { - CVW_EXIT_READ(&hks->hks_familylock); - hook_free(new); + CVW_EXIT_WRITE(&hfi->hfi_lock); + hook_int_free(new, hfi->hfi_stack->hks_netstackid); return (ENXIO); } CVW_ENTER_WRITE(&hei->hei_lock); - /* Multiple hooks are only allowed for read-only events. */ - if (((hei->hei_event->he_flags & HOOK_RDONLY) == 0) && - (!TAILQ_EMPTY(&hei->hei_head))) { - CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&hks->hks_familylock); - hook_free(new); - return (EEXIST); - } - hi = hook_find(hei, h); if (hi != NULL) { + error = EEXIST; + goto bad_add; + } + + if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK, + FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { + error = ENOENT; +bad_add: CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&hks->hks_familylock); - hook_free(new); - return (EEXIST); + CVW_EXIT_WRITE(&hfi->hfi_lock); + hook_int_free(new, hfi->hfi_stack->hks_netstackid); + return (error); } /* Add to hook list head */ - TAILQ_INSERT_HEAD(&hei->hei_head, new, hi_entry); - hei->hei_event->he_interested = B_TRUE; + error = hook_insert(&hei->hei_head, new); + if (error == 0) { + hei->hei_event->he_interested = B_TRUE; + hei->hei_kstats.hooks_added.value.ui64++; + + hook_init_kstats(hfi, hei, new); + } CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&hks->hks_familylock); + CVW_EXIT_WRITE(&hfi->hfi_lock); + + /* + * Note that the name string passed through to the notify callbacks + * is from the original hook being registered, not the copy being + * inserted. + */ + if (error == 0) { + hook_event_notify_run(hei, hfi, event, h->h_name, HN_REGISTER); + hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE); + } + + return (error); +} + +/* + * Function: hook_insert + * Returns: int- 0 = Succ, else = Fail + * Parameters: head(I) - pointer to hook list to insert hook onto + * new(I) - pointer to hook to be inserted + * + * Try to insert the hook onto the list of hooks according to the hints + * given in the hook to be inserted and those that already exist on the + * list. For now, the implementation permits only a single hook to be + * either first or last and names provided with before or after are only + * loosely coupled with the action. + */ +static int +hook_insert(hook_int_head_t *head, hook_int_t *new) +{ + hook_int_t *before; + hook_int_t *hi; + hook_t *hih; + hook_t *h = &new->hi_hook; + + switch (new->hi_hook.h_hint) { + case HH_NONE : + before = NULL; + /* + * If there is no hint present (or not one that can be + * satisfied now) then try to at least respect the wishes + * of those that want to be last. If there are none wanting + * to be last then add the new hook to the tail of the + * list - this means we keep any wanting to be first + * happy without having to search for HH_FIRST. + */ + TAILQ_FOREACH(hi, head, hi_entry) { + hih = &hi->hi_hook; + if ((hih->h_hint == HH_AFTER) && + (strcmp(h->h_name, + (char *)hih->h_hintvalue) == 0)) { + TAILQ_INSERT_BEFORE(hi, new, hi_entry); + return (0); + } + if ((hih->h_hint == HH_BEFORE) && (before == NULL) && + (strcmp(h->h_name, + (char *)hih->h_hintvalue) == 0)) { + before = hi; + } + } + if (before != NULL) { + TAILQ_INSERT_AFTER(head, before, new, hi_entry); + return (0); + } + hook_insert_plain(head, new); + break; + + case HH_FIRST : + hi = TAILQ_FIRST(head); + if ((hi != NULL) && (hi->hi_hook.h_hint == HH_FIRST)) + return (EBUSY); + TAILQ_INSERT_HEAD(head, new, hi_entry); + break; + + case HH_LAST : + hi = TAILQ_LAST(head, hook_int_head); + if ((hi != NULL) && (hi->hi_hook.h_hint == HH_LAST)) + return (EBUSY); + TAILQ_INSERT_TAIL(head, new, hi_entry); + break; + + case HH_BEFORE : + hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue); + if (hi == NULL) + return (hook_insert_afterbefore(head, new)); + + if (hi->hi_hook.h_hint == HH_FIRST) + return (EBUSY); + + TAILQ_INSERT_BEFORE(hi, new, hi_entry); + break; + + case HH_AFTER : + hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue); + if (hi == NULL) + return (hook_insert_afterbefore(head, new)); + + if (hi->hi_hook.h_hint == HH_LAST) + return (EBUSY); + + TAILQ_INSERT_AFTER(head, hi, new, hi_entry); + break; + + default : + return (EINVAL); + } + return (0); } +/* + * Function: hook_insert_plain + * Returns: int- 0 = success, else = failure + * Parameters: head(I) - pointer to hook list to insert hook onto + * new(I) - pointer to hook to be inserted + * + * Insert a hook such that it respects the wishes of those that want to + * be last. If there are none wanting to be last then add the new hook + * to the tail of the list - this means we keep any wanting to be first + * happy without having to search for HH_FIRST. + */ +static void +hook_insert_plain(hook_int_head_t *head, hook_int_t *new) +{ + hook_int_t *hi; + + hi = TAILQ_FIRST(head); + if (hi != NULL) { + if (hi->hi_hook.h_hint == HH_LAST) { + TAILQ_INSERT_BEFORE(hi, new, hi_entry); + } else { + TAILQ_INSERT_TAIL(head, new, hi_entry); + } + } else { + TAILQ_INSERT_TAIL(head, new, hi_entry); + } +} + +/* + * Function: hook_insert_afterbefore + * Returns: int- 0 = success, else = failure + * Parameters: head(I) - pointer to hook list to insert hook onto + * new(I) - pointer to hook to be inserted + * + * Simple insertion of a hook specifying a HH_BEFORE or HH_AFTER was not + * possible, so now we need to be more careful. The first pass is to go + * through the list and look for any other hooks that also specify the + * same hint name as the new one. The object of this exercise is to make + * sure that hooks with HH_BEFORE always appear on the list before those + * with HH_AFTER so that when said hook arrives, it can be placed in the + * middle of the BEFOREs and AFTERs. If this condition does not arise, + * just use hook_insert_plain() to try and insert the hook somewhere that + * is innocuous to existing efforts. + */ +static int +hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new) +{ + hook_int_t *hi; + hook_t *nh; + hook_t *h; + + nh = &new->hi_hook; + ASSERT(new->hi_hook.h_hint != HH_NONE); + ASSERT(new->hi_hook.h_hint != HH_LAST); + ASSERT(new->hi_hook.h_hint != HH_FIRST); + + /* + * First, look through the list to see if there are any other + * before's or after's that have a matching hint name. + */ + TAILQ_FOREACH(hi, head, hi_entry) { + h = &hi->hi_hook; + switch (h->h_hint) { + case HH_FIRST : + case HH_LAST : + case HH_NONE : + break; + case HH_BEFORE : + if ((nh->h_hint == HH_BEFORE) && + (strcmp((char *)h->h_hintvalue, + (char *)nh->h_hintvalue) == 0)) { + TAILQ_INSERT_AFTER(head, hi, new, hi_entry); + return (0); + } + if ((nh->h_hint == HH_AFTER) && + (strcmp((char *)h->h_hintvalue, + (char *)nh->h_hintvalue) == 0)) { + TAILQ_INSERT_BEFORE(hi, new, hi_entry); + return (0); + } + break; + case HH_AFTER : + if ((nh->h_hint == HH_AFTER) && + (strcmp((char *)h->h_hintvalue, + (char *)nh->h_hintvalue) == 0)) { + TAILQ_INSERT_AFTER(head, hi, new, hi_entry); + return (0); + } + if ((nh->h_hint == HH_BEFORE) && + (strcmp((char *)h->h_hintvalue, + (char *)nh->h_hintvalue) == 0)) { + TAILQ_INSERT_BEFORE(hi, new, hi_entry); + return (0); + } + break; + } + } + + hook_insert_plain(head, new); + + return (0); +} /* * Function: hook_unregister @@ -646,19 +1734,18 @@ 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; + boolean_t free_event; ASSERT(hfi != NULL); ASSERT(h != NULL); - hks = (hook_stack_t *)hfi->hfi_ptr; - CVW_ENTER_READ(&hks->hks_familylock); + CVW_ENTER_WRITE(&hfi->hfi_lock); hei = hook_event_find(hfi, event); if (hei == NULL) { - CVW_EXIT_READ(&hks->hks_familylock); + CVW_EXIT_WRITE(&hfi->hfi_lock); return (ENXIO); } @@ -668,23 +1755,72 @@ 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(&hks->hks_familylock); + CVW_EXIT_WRITE(&hfi->hfi_lock); return (ENXIO); } + if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK, + FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { + CVW_EXIT_WRITE(&hei->hei_lock); + CVW_EXIT_WRITE(&hfi->hfi_lock); + return (ENOENT); + } + /* Remove from hook list */ TAILQ_REMOVE(&hei->hei_head, hi, hi_entry); + + free_event = B_FALSE; if (TAILQ_EMPTY(&hei->hei_head)) { hei->hei_event->he_interested = B_FALSE; + /* + * If the delete pending flag has been set and there are + * no notifiers on the event (and we've removed the last + * hook) then we need to free this event after we're done. + */ + if (hei->hei_condemned && TAILQ_EMPTY(&hei->hei_nhead)) + free_event = B_TRUE; } + hei->hei_kstats.hooks_removed.value.ui64++; CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&hks->hks_familylock); + CVW_EXIT_WRITE(&hfi->hfi_lock); + /* + * While the FWF_DEL_ACTIVE flag is set, the hook_event_int_t + * will not be free'd and thus the hook_family_int_t wil not + * be free'd either. + */ + hook_event_notify_run(hei, hfi, event, h->h_name, HN_UNREGISTER); + hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE); + + hook_int_free(hi, hfi->hfi_stack->hks_netstackid); + + if (free_event) + hook_event_free(hei, hfi); - hook_free(hi); return (0); } +/* + * Function: hook_find_byname + * Returns: internal hook pointer - NULL = Not match + * Parameters: hei(I) - internal event pointer + * name(I)- hook name + * + * Search an event's list of hooks to see if there is a hook present that + * has a matching name to the one being looked for. + */ +static hook_int_t * +hook_find_byname(hook_int_head_t *head, char *name) +{ + hook_int_t *hi; + + TAILQ_FOREACH(hi, head, hi_entry) { + if (strcmp(hi->hi_hook.h_name, name) == 0) + return (hi); + } + + return (NULL); +} /* * Function: hook_find @@ -692,25 +1828,20 @@ hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) * Parameters: hei(I) - internal event pointer * h(I) - hook pointer * - * Search hook list - * A lock on familylock must be held when called. + * Search an event's list of hooks to see if there is already one that + * matches the hook being passed in. Currently the only criteria for a + * successful search here is for the names to be the same. */ static hook_int_t * hook_find(hook_event_int_t *hei, hook_t *h) { - hook_int_t *hi; ASSERT(hei != NULL); ASSERT(h != NULL); - TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) { - if (strcmp(hi->hi_hook.h_name, h->h_name) == 0) - break; - } - return (hi); + return (hook_find_byname(&hei->hei_head, h->h_name)); } - /* * Function: hook_copy * Returns: internal hook pointer - NULL = Failed @@ -718,12 +1849,17 @@ hook_find(hook_event_int_t *hei, hook_t *h) * * Allocate internal hook block and duplicate incoming hook. * No locks should be held across this function as it may sleep. + * Because hook_copy() is responsible for the creation of the internal + * hook structure that is used here, it takes on population the structure + * with the kstat information. Note that while the kstat bits are + * seeded here, their installation of the kstats is handled elsewhere. */ static hook_int_t * hook_copy(hook_t *src) { hook_int_t *new; hook_t *dst; + int len; ASSERT(src != NULL); ASSERT(src->h_name != NULL); @@ -735,29 +1871,278 @@ hook_copy(hook_t *src) *dst = *src; /* Copy name */ - dst->h_name = (char *)kmem_alloc(strlen(src->h_name) + 1, KM_SLEEP); + len = strlen(src->h_name); + dst->h_name = (char *)kmem_alloc(len + 1, KM_SLEEP); (void) strcpy(dst->h_name, src->h_name); + /* + * This is initialised in this manner to make it safer to use the + * same pointer in the kstats field. + */ + dst->h_hintvalue = (uintptr_t)""; + + if (dst->h_hint == HH_BEFORE || dst->h_hint == HH_AFTER) { + len = strlen((char *)src->h_hintvalue); + if (len > 0) { + dst->h_hintvalue = (uintptr_t)kmem_alloc(len + 1, + KM_SLEEP); + (void) strcpy((char *)dst->h_hintvalue, + (char *)src->h_hintvalue); + } + } + return (new); } /* - * Function: hook_free + * Function: hook_init_kstats + * Returns: None + * Parameters: hfi(I) - pointer to the family that owns the event. + * hei(I) - pointer to the event that owns this hook + * hi(I) - pointer to the hook for which we create kstats for + * + * Each hook that is registered with this framework has its own kstats + * set up so that we can provide an easy way in which to observe the + * look of hooks (using the kstat command.) The position is set to 0 + * here but is recalculated after we know the insertion has been a + * success. + */ +static void +hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, hook_int_t *hi) +{ + hook_hook_kstat_t template = { + { "version", KSTAT_DATA_INT32 }, + { "flags", KSTAT_DATA_UINT32 }, + { "hint", KSTAT_DATA_INT32 }, + { "hint_value", KSTAT_DATA_UINT64 }, + { "position", KSTAT_DATA_INT32 }, + { "hook_hits", KSTAT_DATA_UINT64 } + }; + hook_stack_t *hks; + size_t kslen; + int position; + hook_int_t *h; + + kslen = strlen(hfi->hfi_family.hf_name) + + strlen(hei->hei_event->he_name) + 2; + + hi->hi_ksname = (char *)kmem_zalloc(kslen, KM_SLEEP); + (void) snprintf(hi->hi_ksname, kslen, "%s/%s", + hfi->hfi_family.hf_name, hei->hei_event->he_name); + + hks = hfi->hfi_stack; + hi->hi_kstatp = kstat_create_netstack(hi->hi_ksname, 0, + hi->hi_hook.h_name, "hook", KSTAT_TYPE_NAMED, + sizeof (hi->hi_kstats) / sizeof (kstat_named_t), + KSTAT_FLAG_VIRTUAL, hks->hks_netstackid); + + /* Initialise the kstats for the structure */ + bcopy(&template, &hi->hi_kstats, sizeof (template)); + hi->hi_kstats.hook_version.value.i32 = hi->hi_hook.h_version; + hi->hi_kstats.hook_flags.value.ui32 = hi->hi_hook.h_flags; + hi->hi_kstats.hook_hint.value.i32 = hi->hi_hook.h_hint; + hi->hi_kstats.hook_position.value.i32 = 0; + hi->hi_kstats.hook_hits.value.ui64 = 0; + + switch (hi->hi_hook.h_hint) { + case HH_BEFORE : + case HH_AFTER : + hi->hi_kstats.hook_hintvalue.data_type = KSTAT_DATA_STRING; + hi->hi_kstats.hook_hintvalue.value.ui64 = + hi->hi_hook.h_hintvalue; + break; + default : + break; + } + + if (hi->hi_kstatp != NULL) { + hi->hi_kstatp->ks_data = (void *)&hi->hi_kstats; + hi->hi_kstatp->ks_private = + (void *)(uintptr_t)hks->hks_netstackid; + + kstat_install(hi->hi_kstatp); + } + + position = 1; + TAILQ_FOREACH(h, &hei->hei_head, hi_entry) { + h->hi_kstats.hook_position.value.ui32 = position++; + } +} + +/* + * Function: hook_int_free * Returns: None * Parameters: hi(I) - internal hook pointer * * Free alloc memory for hook */ static void -hook_free(hook_int_t *hi) +hook_int_free(hook_int_t *hi, netstackid_t stackid) { + int len; + ASSERT(hi != NULL); /* Free name space */ if (hi->hi_hook.h_name != NULL) { kmem_free(hi->hi_hook.h_name, strlen(hi->hi_hook.h_name) + 1); } + if (hi->hi_ksname != NULL) { + kmem_free(hi->hi_ksname, strlen(hi->hi_ksname) + 1); + } + + /* Free the name used with the before/after hints. */ + switch (hi->hi_hook.h_hint) { + case HH_BEFORE : + case HH_AFTER : + len = strlen((char *)hi->hi_hook.h_hintvalue); + if (len > 0) + kmem_free((void *)hi->hi_hook.h_hintvalue, len + 1); + break; + default : + break; + } + + if (hi->hi_kstatp != NULL) + kstat_delete_netstack(hi->hi_kstatp, stackid); /* Free container */ kmem_free(hi, sizeof (*hi)); } + +/* + * Function: hook_alloc + * Returns: hook_t * - pointer to new hook structure + * Parameters: version(I) - version number of the API when compiled + * + * This function serves as the interface for consumers to obtain a hook_t + * structure. At this point in time, there is only a single "version" of + * it, leading to a straight forward function. In a perfect world the + * h_vesion would be a protected data structure member, but C isn't that + * advanced... + */ +hook_t * +hook_alloc(const int h_version) +{ + hook_t *h; + + h = kmem_zalloc(sizeof (hook_t), KM_SLEEP); + h->h_version = h_version; + return (h); +} + +/* + * Function: hook_free + * Returns: None + * Parameters: h(I) - external hook pointer + * + * This function only free's memory allocated with hook_alloc(), so that if + * (for example) kernel memory was allocated for h_name, this needs to be + * free'd before calling hook_free(). + */ +void +hook_free(hook_t *h) +{ + kmem_free(h, sizeof (*h)); +} + +/* + * Function: hook_notify_register + * Returns: 0 = success, else failure + * Parameters: lock(I) - netstack identifier + * head(I) - top of the list of callbacks + * callback(I) - function to be called + * arg(I) - arg to pass back to the function + * + * This function implements the modification of the list of callbacks + * that are registered when someone wants to be advised of a change + * that has happened. + */ +static int +hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head, + hook_notify_fn_t callback, void *arg) +{ + hook_notify_t *hn; + + CVW_ENTER_WRITE(lock); + + TAILQ_FOREACH(hn, head, hn_entry) { + if (hn->hn_func == callback) { + CVW_EXIT_WRITE(lock); + return (EEXIST); + } + } + + hn = (hook_notify_t *)kmem_alloc(sizeof (*hn), KM_SLEEP); + hn->hn_func = callback; + hn->hn_arg = arg; + TAILQ_INSERT_TAIL(head, hn, hn_entry); + + CVW_EXIT_WRITE(lock); + + return (0); +} + +/* + * Function: hook_stack_notify_register + * Returns: 0 = success, else failure + * Parameters: stackid(I) - netstack identifier + * callback(I) - function to be called + * + */ +static int +hook_notify_unregister(cvwaitlock_t *lock, hook_notify_head_t *head, + hook_notify_fn_t callback) +{ + hook_notify_t *hn; + + CVW_ENTER_WRITE(lock); + + TAILQ_FOREACH(hn, head, hn_entry) { + if (hn->hn_func == callback) + break; + } + if (hn == NULL) { + CVW_EXIT_WRITE(lock); + return (ESRCH); + } + + TAILQ_REMOVE(head, hn, hn_entry); + + CVW_EXIT_WRITE(lock); + + kmem_free(hn, sizeof (*hn)); + + return (0); +} + +/* + * Function: hook_notify_run + * Returns: None + * Parameters: head(I) - top of the list of callbacks + * family(I) - name of the hook family that owns the event + * event(I) - name of the event being changed + * name(I) - name of the object causing change + * cmd(I) - either HN_UNREGISTER or HN_REGISTER + * + * This function walks through the list of registered callbacks and + * executes each one, passing back the arg supplied when registered + * and the name of the family (that owns the event), event (the thing + * to which we're making a change) and finally a name that describes + * what is being added or removed, as indicated by cmd. + * + * This function does not acquire or release any lock as it is required + * that code calling it do so before hand. The use of hook_notify_head_t + * is protected by the use of flagwait_t in the structures that own this + * list and with the use of the FWF_ADD/DEL_ACTIVE flags. + */ +static void +hook_notify_run(hook_notify_head_t *head, char *family, char *event, + char *name, hook_notify_cmd_t cmd) +{ + hook_notify_t *hn; + + TAILQ_FOREACH(hn, head, hn_entry) { + (*hn->hn_func)(cmd, hn->hn_arg, family, event, name); + } +} diff --git a/usr/src/uts/common/io/neti.c b/usr/src/uts/common/io/neti.c deleted file mode 100644 index 49a17ee91f..0000000000 --- a/usr/src/uts/common/io/neti.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/param.h> -#include <sys/atomic.h> -#include <sys/kmem.h> -#include <sys/rwlock.h> -#include <sys/errno.h> -#include <sys/queue.h> -#include <inet/common.h> -#include <inet/led.h> -#include <inet/ip.h> -#include <sys/modctl.h> -#include <sys/neti.h> - - -static void net_init(); -static void net_fini(); -static net_data_t net_find(const char *protocol, neti_stack_t *ns); -static void *neti_stack_init(netstackid_t stackid, netstack_t *ns); -static void neti_stack_fini(netstackid_t stackid, void *arg); - -/* - * Module linkage information for the kernel. - */ -static struct modldrv modlmisc = { - &mod_miscops, /* drv_modops */ - "netinfo module 1.0", /* drv_linkinfo */ -}; - -static struct modlinkage modlinkage = { - MODREV_1, /* ml_rev */ - &modlmisc, /* ml_linkage */ - NULL -}; - -/* - * Module entry points. - */ -int -_init(void) -{ - int error; - - net_init(); - error = mod_install(&modlinkage); - if (error != 0) - net_fini(); - - return (error); -} - - -int -_fini(void) -{ - int error; - - error = mod_remove(&modlinkage); - if (error == 0) - net_fini(); - - return (error); -} - - -int -_info(struct modinfo *modinfop) -{ - - return (mod_info(&modlinkage, modinfop)); -} - - -static void -net_init() -{ - /* - * We want to be informed each time a stack is created or - * destroyed in the kernel. - */ - netstack_register(NS_NETI, neti_stack_init, NULL, - neti_stack_fini); -} - -static void -net_fini() -{ - netstack_unregister(NS_NETI); -} - - -/* - * Initialize the neti stack instance. - */ -/*ARGSUSED*/ -static void * -neti_stack_init(netstackid_t stackid, netstack_t *ns) -{ - neti_stack_t *nts; - -#ifdef NS_DEBUG - printf("neti_stack_init(stack %d)\n", stackid); -#endif - - nts = (neti_stack_t *)kmem_zalloc(sizeof (*nts), KM_SLEEP); - nts->nts_netstack = ns; - - rw_init(&nts->nts_netlock, NULL, RW_DRIVER, NULL); - LIST_INIT(&nts->nts_netd_head); - - return (nts); -} - - -/* - * Free the neti stack instance. - */ -/*ARGSUSED*/ -static void -neti_stack_fini(netstackid_t stackid, void *arg) -{ - neti_stack_t *nts = (neti_stack_t *)arg; -#ifdef NS_DEBUG - printf("neti_stack_fini(%p, stack %d)\n", arg, stackid); -#endif - rw_destroy(&nts->nts_netlock); - kmem_free(nts, sizeof (*nts)); -} - - -static net_data_t -net_find(const char *protocol, neti_stack_t *nts) -{ - struct net_data *n; - - ASSERT(protocol != NULL); - - LIST_FOREACH(n, &nts->nts_netd_head, netd_list) { - ASSERT(n->netd_info.neti_protocol != NULL); - if (strcmp(n->netd_info.neti_protocol, protocol) == 0) { - break; - } - } - - return (n); -} - -net_data_t -net_register(const net_info_t *info, netstackid_t nsid) -{ - netstack_t *ns; - net_data_t nd; - - ns = netstack_find_by_stackid(nsid); - nd = net_register_impl(info, ns); - netstack_rele(ns); - - return (nd); -} - -net_data_t -net_register_impl(const net_info_t *info, netstack_t *ns) -{ - struct net_data *n, *new; - struct neti_stack *nts; - - ASSERT(info != NULL); - ASSERT(ns != NULL); - - nts = ns->netstack_neti; - - new = kmem_alloc(sizeof (*new), KM_SLEEP); - new->netd_refcnt = 0; - new->netd_hooks = NULL; - new->netd_info = *info; - new->netd_netstack = ns; - - rw_enter(&nts->nts_netlock, RW_WRITER); - n = net_find(info->neti_protocol, nts); - if (n != NULL) { - rw_exit(&nts->nts_netlock); - kmem_free(new, sizeof (*new)); - return (NULL); - } - - if (LIST_EMPTY(&nts->nts_netd_head)) - LIST_INSERT_HEAD(&nts->nts_netd_head, new, netd_list); - else - LIST_INSERT_AFTER(LIST_FIRST(&nts->nts_netd_head), - new, netd_list); - - rw_exit(&nts->nts_netlock); - return (new); -} - - -int -net_unregister(net_data_t info) -{ - struct netstack *ns; - struct neti_stack *nts; - ns = info->netd_netstack; - nts = ns->netstack_neti; - - ASSERT(info != NULL); - - rw_enter(&nts->nts_netlock, RW_WRITER); - if (info->netd_refcnt != 0) { - rw_exit(&nts->nts_netlock); - return (EBUSY); - } - - LIST_REMOVE(info, netd_list); - - rw_exit(&nts->nts_netlock); - - kmem_free(info, sizeof (struct net_data)); - return (0); -} - -net_data_t -net_lookup(const char *protocol, netstackid_t nsid) -{ - netstack_t *ns; - net_data_t nd; - - ns = netstack_find_by_stackid(nsid); - nd = net_lookup_impl(protocol, ns); - netstack_rele(ns); - - return (nd); -} - -net_data_t -net_lookup_impl(const char *protocol, netstack_t *ns) -{ - struct net_data *n; - struct neti_stack *nts; - - ASSERT(protocol != NULL); - ASSERT(ns != NULL); - - nts = ns->netstack_neti; - - rw_enter(&nts->nts_netlock, RW_READER); - n = net_find(protocol, nts); - if (n != NULL) - atomic_add_32((uint_t *)&n->netd_refcnt, 1); - rw_exit(&nts->nts_netlock); - return (n); -} - -/* - * Note: the man page specifies "returns -1 if the value passed in is unknown - * to this framework". We are not doing a lookup in this function, just a - * simply add to the netd_refcnt of the net_data_t passed in, so -1 is never a - * return value. - */ -int -net_release(net_data_t info) -{ - struct netstack *ns; - struct neti_stack *nts; - - ns = info->netd_netstack; - nts = ns->netstack_neti; - - ASSERT(info != NULL); - - rw_enter(&nts->nts_netlock, RW_READER); - ASSERT(info->netd_refcnt > 0); - atomic_add_32((uint_t *)&info->netd_refcnt, -1); - - /* net_release has been called too many times */ - if (info->netd_refcnt < 0) { - rw_exit(&nts->nts_netlock); - return (1); - } - rw_exit(&nts->nts_netlock); - - return (0); -} - -net_data_t -net_walk(net_data_t info, netstackid_t nsid) -{ - netstack_t *ns; - net_data_t nd; - - ns = netstack_find_by_stackid(nsid); - nd = net_walk_impl(info, ns); - netstack_rele(ns); - - return (nd); -} - -net_data_t -net_walk_impl(net_data_t info, netstack_t *ns) -{ - struct net_data *n = NULL; - boolean_t found = B_FALSE; - struct neti_stack *nts; - - ASSERT(ns != NULL); - - nts = ns->netstack_neti; - - if (info == NULL) - found = B_TRUE; - - rw_enter(&nts->nts_netlock, RW_READER); - LIST_FOREACH(n, &nts->nts_netd_head, netd_list) { - if (found) - break; - if (n == info) - found = B_TRUE; - } - - if (info != NULL) { - ASSERT(info->netd_refcnt > 0); - atomic_add_32((uint_t *)&info->netd_refcnt, -1); - } - if (n != NULL) - atomic_add_32((uint_t *)&n->netd_refcnt, 1); - - rw_exit(&nts->nts_netlock); - - return (n); -} - - -/* - * Public accessor functions - */ -int -net_getifname(net_data_t info, phy_if_t phy_ifdata, - char *buffer, const size_t buflen) -{ - - ASSERT(info != NULL); - - return (info->netd_info.neti_getifname(phy_ifdata, buffer, buflen, - info->netd_netstack)); -} - - -int -net_getmtu(net_data_t info, phy_if_t phy_ifdata, lif_if_t ifdata) -{ - - ASSERT(info != NULL); - - return (info->netd_info.neti_getmtu(phy_ifdata, ifdata, - info->netd_netstack)); -} - - -int -net_getpmtuenabled(net_data_t info) -{ - - ASSERT(info != NULL); - - return (info->netd_info.neti_getpmtuenabled(info->netd_netstack)); -} - - -int -net_getlifaddr(net_data_t info, phy_if_t phy_ifdata, lif_if_t ifdata, - int nelem, net_ifaddr_t type[], void *storage) -{ - - ASSERT(info != NULL); - - return (info->netd_info.neti_getlifaddr(phy_ifdata, ifdata, - nelem, type, storage, info->netd_netstack)); -} - - -phy_if_t -net_phygetnext(net_data_t info, phy_if_t phy_ifdata) -{ - - ASSERT(info != NULL); - - return (info->netd_info.neti_phygetnext(phy_ifdata, - info->netd_netstack)); -} - - -phy_if_t -net_phylookup(net_data_t info, const char *name) -{ - - ASSERT(info != NULL); - - return (info->netd_info.neti_phylookup(name, info->netd_netstack)); -} - - -lif_if_t -net_lifgetnext(net_data_t info, phy_if_t ifidx, lif_if_t ifdata) -{ - - ASSERT(info != NULL); - - return (info->netd_info.neti_lifgetnext(ifidx, ifdata, - info->netd_netstack)); -} - - -int -net_inject(net_data_t info, inject_t style, net_inject_t *packet) -{ - - ASSERT(info != NULL); - - return (info->netd_info.neti_inject(style, packet, - info->netd_netstack)); -} - - -phy_if_t -net_routeto(net_data_t info, struct sockaddr *address) -{ - - ASSERT(info != NULL); - - return (info->netd_info.neti_routeto(address, info->netd_netstack)); -} - - -int -net_ispartialchecksum(net_data_t info, mblk_t *mp) -{ - - ASSERT(info != NULL); - ASSERT(mp != NULL); - - return (info->netd_info.neti_ispartialchecksum(mp)); -} - - -int -net_isvalidchecksum(net_data_t info, mblk_t *mp) -{ - - ASSERT(info != NULL); - ASSERT(mp != NULL); - - return (info->netd_info.neti_isvalidchecksum(mp)); -} - - -/* - * Hooks related functions - */ - -/* - * Function: net_register_family - * Returns: int - 0 = Succ, Else = Fail - * Parameters: info(I) - protocol - * hf(I) - family pointer - * - * Call hook_family_add to register family - */ -int -net_register_family(net_data_t info, hook_family_t *hf) -{ - hook_family_int_t *hfi; - - ASSERT(info != NULL); - ASSERT(hf != NULL); - - if (info->netd_hooks != NULL) - return (EEXIST); - - hfi = hook_family_add(hf, info->netd_netstack->netstack_hook); - if (hfi == NULL) - return (EEXIST); - - info->netd_hooks = hfi; - return (0); -} - - -/* - * Function: net_unregister_family - * Returns: int - transparent value, explained by caller - * Parameters: info(I) - protocol - * hf(I) - family pointer - * - * Call hook_family_remove to unregister family - */ -int -net_unregister_family(net_data_t info, hook_family_t *hf) -{ - int ret; - - ASSERT(info != NULL); - ASSERT(hf != NULL); - - if (info->netd_hooks == NULL) - return (ENXIO); - - if (strcmp(info->netd_hooks->hfi_family.hf_name, - hf->hf_name) != 0) - return (EINVAL); - - ret = hook_family_remove(info->netd_hooks); - if (ret == 0) - info->netd_hooks = NULL; - - return (ret); -} - - -/* - * Function: net_register_event - * Returns: internal event pointer - NULL = Fail - * Parameters: info(I) - protocol - * he(I) - event pointer - * - * Call hook_event_add to register event on specific family - * Internal event pointer is returned so caller can get - * handle to run hooks - */ -hook_event_token_t -net_register_event(net_data_t info, hook_event_t *he) -{ - hook_event_int_t *hei; - - ASSERT(info != NULL); - ASSERT(he != NULL); - - if (info->netd_hooks == NULL) - return (NULL); - - hei = hook_event_add(info->netd_hooks, he); - return ((hook_event_token_t)hei); -} - - -/* - * Function: net_unregister_event - * Returns: int - transparent value, explained by caller - * Parameters: info(I) - protocol - * he(I) - event pointer - * - * Call hook_event_remove to unregister event on specific family - */ -int -net_unregister_event(net_data_t info, hook_event_t *he) -{ - - ASSERT(info != NULL); - ASSERT(he != NULL); - - if (info->netd_hooks == NULL) - return (ENXIO); - - return (hook_event_remove(info->netd_hooks, he)); -} - - -/* - * Function: net_register_hook - * Returns: int - transparent value, explained by caller - * Parameters: info(I) - protocol - * event(I) - event name - * h(I) - hook pointer - * - * Call hook_register to add hook on specific family/event - */ -int -net_register_hook(net_data_t info, char *event, hook_t *h) -{ - - ASSERT(info != NULL); - ASSERT(event != NULL); - ASSERT(h != NULL); - - if (info->netd_hooks == NULL) - return (ENXIO); - - return (hook_register(info->netd_hooks, event, h)); -} - - -/* - * Function: net_unregister_hook - * Returns: int - transparent value, explained by caller - * Parameters: info(I) - protocol - * event(I) - event name - * h(I) - hook pointer - * - * Call hook_unregister to remove hook on specific family/event - */ -int -net_unregister_hook(net_data_t info, char *event, hook_t *h) -{ - - ASSERT(info != NULL); - ASSERT(event != NULL); - ASSERT(h != NULL); - - if (info->netd_hooks == NULL) - return (ENXIO); - - return (hook_unregister(info->netd_hooks, event, h)); -} diff --git a/usr/src/uts/common/io/neti_impl.c b/usr/src/uts/common/io/neti_impl.c new file mode 100644 index 0000000000..346e49903d --- /dev/null +++ b/usr/src/uts/common/io/neti_impl.c @@ -0,0 +1,621 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/param.h> +#include <sys/atomic.h> +#include <sys/kmem.h> +#include <sys/rwlock.h> +#include <sys/errno.h> +#include <sys/queue.h> +#include <inet/common.h> +#include <inet/led.h> +#include <inet/ip.h> +#include <sys/neti.h> +#include <sys/zone.h> + +static net_handle_t net_find(const char *protocol, neti_stack_t *ns); + +static net_handle_t +net_find(const char *protocol, neti_stack_t *nts) +{ + struct net_data *n; + + ASSERT(protocol != NULL); + ASSERT(nts != NULL); + + LIST_FOREACH(n, &nts->nts_netd_head, netd_list) { + ASSERT(n->netd_info.netp_name != NULL); + /* + * If they're trying to find a protocol that is being + * shutdown, just ignore it.. + */ + if (n->netd_condemned != 0) + continue; + if (strcmp(n->netd_info.netp_name, protocol) == 0) { + break; + } + } + + return (n); +} + +net_handle_t +net_protocol_register(netid_t id, const net_protocol_t *info) +{ + struct net_data *n, *new; + neti_stack_t *nts; + + ASSERT(info != NULL); + + nts = net_getnetistackbyid(id); + if (nts == NULL) + return (NULL); + + new = kmem_alloc(sizeof (*new), KM_SLEEP); + new->netd_refcnt = 1; + new->netd_hooks = NULL; + new->netd_info = *info; + new->netd_stack = nts; + new->netd_condemned = 0; + + mutex_enter(&nts->nts_lock); + n = net_find(info->netp_name, nts); + if (n != NULL) { + mutex_exit(&nts->nts_lock); + kmem_free(new, sizeof (*new)); + return (NULL); + } + + if (LIST_EMPTY(&nts->nts_netd_head)) { + LIST_INSERT_HEAD(&nts->nts_netd_head, new, netd_list); + } else { + LIST_INSERT_AFTER(LIST_FIRST(&nts->nts_netd_head), + new, netd_list); + } + mutex_exit(&nts->nts_lock); + + return (new); +} + +int +net_protocol_unregister(net_handle_t info) +{ + neti_stack_t *nts; + + ASSERT(info != NULL); + + nts = info->netd_stack; + ASSERT(nts != NULL); + + mutex_enter(&nts->nts_lock); + LIST_REMOVE(info, netd_list); + info->netd_stack = NULL; + mutex_exit(&nts->nts_lock); + + (void) net_protocol_release(info); + + return (0); +} + +net_handle_t +net_protocol_lookup(netid_t netid, const char *protocol) +{ + neti_stack_t *nts; + net_handle_t nd; + + ASSERT(protocol != NULL); + + nts = net_getnetistackbyid(netid); + if (nts == NULL) + return (NULL); + + mutex_enter(&nts->nts_lock); + nd = net_find(protocol, nts); + if (nd != NULL) + atomic_add_32((uint_t *)&nd->netd_refcnt, 1); + mutex_exit(&nts->nts_lock); + return (nd); +} + +/* + * Note: the man page specifies "returns -1 if the value passed in is unknown + * to this framework". We are not doing a lookup in this function, just a + * simply add to the netd_refcnt of the net_handle_t passed in, so -1 is never a + * return value. + */ +int +net_protocol_release(net_handle_t info) +{ + + ASSERT(info->netd_refcnt > 0); + /* + * Is this safe? No hold on nts_lock? Consider that if the caller + * of net_protocol_release() is going to free this structure then + * it is now the only owner (refcnt==1) and it will have been + * removed from the nts_netd_head list on the neti_stack_t from a + * call to net_protocol_unregister already, so it is thus an orphan. + */ + if (atomic_add_32_nv((uint_t *)&info->netd_refcnt, -1) == 0) { + ASSERT(info->netd_hooks == NULL); + ASSERT(info->netd_stack == NULL); + kmem_free(info, sizeof (struct net_data)); + } + + return (0); +} + +net_handle_t +net_protocol_walk(netid_t netid, net_handle_t info) +{ + struct net_data *n = NULL; + boolean_t found = B_FALSE; + neti_stack_t *nts; + + nts = net_getnetistackbyid(netid); + ASSERT(nts != NULL); + + if (info == NULL) + found = B_TRUE; + + mutex_enter(&nts->nts_lock); + LIST_FOREACH(n, &nts->nts_netd_head, netd_list) { + if (found) { + /* + * We are only interested in finding protocols that + * are not in some sort of shutdown state. There is + * no need to check for netd_stack==NULL because + * that implies it is no longer on this list. + */ + if (n->netd_condemned == 0) + continue; + break; + } + + if (n == info) + found = B_TRUE; + } + + if (info != NULL) + (void) net_protocol_release(info); + + if (n != NULL) + atomic_add_32((uint_t *)&n->netd_refcnt, 1); + + mutex_exit(&nts->nts_lock); + + return (n); +} + +/* + * Public accessor functions + */ +int +net_getifname(net_handle_t info, phy_if_t nic, char *buffer, + const size_t buflen) +{ + + ASSERT(info != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return (-1); + + return (info->netd_info.netp_getifname(info, nic, buffer, buflen)); +} + +int +net_getmtu(net_handle_t info, phy_if_t nic, lif_if_t ifdata) +{ + + ASSERT(info != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return (-1); + + return (info->netd_info.netp_getmtu(info, nic, ifdata)); +} + +int +net_getpmtuenabled(net_handle_t info) +{ + + ASSERT(info != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return (-1); + + return (info->netd_info.netp_getpmtuenabled(info)); +} + +int +net_getlifaddr(net_handle_t info, phy_if_t nic, lif_if_t ifdata, + int nelem, net_ifaddr_t type[], void *storage) +{ + + ASSERT(info != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return (-1); + + return (info->netd_info.netp_getlifaddr(info, nic, ifdata, + nelem, type, storage)); +} + +phy_if_t +net_phygetnext(net_handle_t info, phy_if_t nic) +{ + + ASSERT(info != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return ((phy_if_t)-1); + + return (info->netd_info.netp_phygetnext(info, nic)); +} + +phy_if_t +net_phylookup(net_handle_t info, const char *name) +{ + + ASSERT(info != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return ((phy_if_t)-1); + + return (info->netd_info.netp_phylookup(info, name)); +} + +lif_if_t +net_lifgetnext(net_handle_t info, phy_if_t ifidx, lif_if_t ifdata) +{ + + ASSERT(info != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return ((lif_if_t)-1); + + return (info->netd_info.netp_lifgetnext(info, ifidx, ifdata)); +} + +int +net_inject(net_handle_t info, inject_t style, net_inject_t *packet) +{ + + ASSERT(info != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return (-1); + + return (info->netd_info.netp_inject(info, style, packet)); +} + +phy_if_t +net_routeto(net_handle_t info, struct sockaddr *address, struct sockaddr *next) +{ + + ASSERT(info != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return ((phy_if_t)-1); + + return (info->netd_info.netp_routeto(info, address, next)); +} + +int +net_ispartialchecksum(net_handle_t info, mblk_t *mp) +{ + + ASSERT(info != NULL); + ASSERT(mp != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return (-1); + + return (info->netd_info.netp_ispartialchecksum(info, mp)); +} + +int +net_isvalidchecksum(net_handle_t info, mblk_t *mp) +{ + + ASSERT(info != NULL); + ASSERT(mp != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return (-1); + + return (info->netd_info.netp_isvalidchecksum(info, mp)); +} + +/* + * Hooks related functions + */ + +/* + * Function: net_family_register + * Returns: int - 0 = Succ, Else = Fail + * Parameters: info(I) - protocol + * hf(I) - family pointer + * + * Call hook_family_add to register family + * + * There is no need to bump netd_refcnt in the two functions + * net_family_register and net_family_unregister because the caller of these + * two functions is assumed to "own" a reference on 'info' via an earlier + * call to net_protocol_register(). Thus the owner is expected to do a + * call to net_protocol_unregister() after having done a + * net_family_unregister() to make sure things are properly cleaned up. + */ +int +net_family_register(net_handle_t info, hook_family_t *hf) +{ + hook_family_int_t *hfi; + netstack_t *ns; + + ASSERT(info != NULL); + ASSERT(hf != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return (ESHUTDOWN); + + if (info->netd_hooks != NULL) + return (EEXIST); + + ns = info->netd_stack->nts_netstack; + ASSERT(ns != NULL); + hfi = hook_family_add(hf, ns->netstack_hook); + if (hfi == NULL) + return (EEXIST); + + info->netd_hooks = hfi; + return (0); +} + +/* + * Function: net_family_unregister + * Returns: int - transparent value, explained by caller + * Parameters: info(I) - protocol + * hf(I) - family pointer + * + * Call hook_family_remove to unregister family + */ +int +net_family_unregister(net_handle_t info, hook_family_t *hf) +{ + int ret; + + ASSERT(info != NULL); + ASSERT(hf != NULL); + + if (info->netd_hooks == NULL) + return (ENXIO); + + if (strcmp(info->netd_hooks->hfi_family.hf_name, + hf->hf_name) != 0) + return (EINVAL); + + ret = hook_family_remove(info->netd_hooks); + if (ret == 0) + info->netd_hooks = NULL; + + return (ret); +} + +/* + * Function: net_event_register + * Returns: internal event pointer - NULL = Fail + * Parameters: info(I) - protocol + * he(I) - event pointer + * + * Call hook_event_add to register event on specific family + * Internal event pointer is returned so caller can get + * handle to run hooks + */ +hook_event_token_t +net_event_register(net_handle_t info, hook_event_t *he) +{ + hook_event_int_t *hei; + + ASSERT(info != NULL); + ASSERT(he != NULL); + + if (info->netd_hooks == NULL || info->netd_condemned != 0 || + info->netd_stack == NULL) + return (NULL); + + hei = hook_event_add(info->netd_hooks, he); + return ((hook_event_token_t)hei); +} + +/* + * Function: net_event_unregister + * Returns: int - transparent value, explained by caller + * Parameters: info(I) - protocol + * he(I) - event pointer + * + * Call hook_event_remove to unregister event on specific family + */ +int +net_event_unregister(net_handle_t info, hook_event_t *he) +{ + + ASSERT(info != NULL); + ASSERT(he != NULL); + + if (info->netd_hooks == NULL) + return (ENXIO); + + return (hook_event_remove(info->netd_hooks, he)); +} + +/* + * Function: net_hook_register + * Returns: int - transparent value, explained by caller + * Parameters: info(I) - protocol + * event(I) - event name + * h(I) - hook pointer + * + * Call hook_register to add hook on specific family/event + */ +int +net_hook_register(net_handle_t info, char *event, hook_t *h) +{ + + ASSERT(info != NULL); + ASSERT(event != NULL); + ASSERT(h != NULL); + + if (info->netd_condemned != 0 || info->netd_stack == NULL) + return (ESHUTDOWN); + + if (info->netd_hooks == NULL) + return (ENXIO); + + return (hook_register(info->netd_hooks, event, h)); +} + +/* + * Function: net_hook_unregister + * Returns: int - transparent value, explained by caller + * Parameters: info(I) - protocol + * event(I) - event name + * h(I) - hook pointer + * + * Call hook_unregister to remove hook on specific family/event + */ +int +net_hook_unregister(net_handle_t info, char *event, hook_t *h) +{ + + ASSERT(info != NULL); + ASSERT(event != NULL); + ASSERT(h != NULL); + + if (info->netd_hooks == NULL) + return (ENXIO); + + return (hook_unregister(info->netd_hooks, event, h)); +} + +netid_t +net_getnetid(net_handle_t netd) +{ + + if (netd->netd_stack == NULL) + return (-1); + return (netd->netd_stack->nts_id); +} + +net_inject_t * +net_inject_alloc(const int version) +{ + net_inject_t *ni; + + ni = kmem_zalloc(sizeof (*ni), KM_NOSLEEP); + if (ni == NULL) + return (NULL); + + ni->ni_version = version; + return (ni); +} + +void +net_inject_free(net_inject_t *ni) +{ + kmem_free(ni, sizeof (*ni)); +} + +kstat_t * +net_kstat_create(netid_t netid, char *module, int instance, char *name, + char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag) +{ + netstackid_t stackid = net_getnetstackidbynetid(netid); + + if (stackid == -1) + return (NULL); + + return (kstat_create_netstack(module, instance, name, class, type, + ndata, ks_flag, stackid)); +} + +void +net_kstat_delete(netid_t netid, kstat_t *ks) +{ + netstackid_t stackid = net_getnetstackidbynetid(netid); + + if (stackid != -1) + kstat_delete_netstack(ks, stackid); +} + +int +net_event_notify_register(net_handle_t family, char *event, + hook_notify_fn_t callback, void *arg) +{ + int error; + + if (family->netd_condemned != 0 || family->netd_stack == NULL) + return (ESHUTDOWN); + + error = hook_event_notify_register(family->netd_hooks, event, + callback, arg); + + return (error); +} + +int +net_event_notify_unregister(net_handle_t family, char *event, + hook_notify_fn_t callback) +{ + int error; + + error = hook_event_notify_unregister(family->netd_hooks, event, + callback); + + return (error); +} + +int +net_protocol_notify_register(net_handle_t family, hook_notify_fn_t callback, + void *arg) +{ + int error; + + if (family->netd_condemned != 0 || family->netd_stack == NULL) + return (ESHUTDOWN); + + error = hook_family_notify_register(family->netd_hooks, callback, + arg); + + return (error); +} + +int +net_protocol_notify_unregister(net_handle_t family, hook_notify_fn_t callback) +{ + int error; + + error = hook_family_notify_unregister(family->netd_hooks, callback); + + return (error); +} diff --git a/usr/src/uts/common/io/neti_mod.c b/usr/src/uts/common/io/neti_mod.c new file mode 100644 index 0000000000..ad0bcbc2e4 --- /dev/null +++ b/usr/src/uts/common/io/neti_mod.c @@ -0,0 +1,80 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/param.h> +#include <sys/modctl.h> +#include <sys/neti.h> + + +/* + * Module linkage information for the kernel. + */ +static struct modldrv modlmisc = { + &mod_miscops, /* drv_modops */ + "netinfo module", /* drv_linkinfo */ +}; + +static struct modlinkage modlinkage = { + MODREV_1, /* ml_rev */ + &modlmisc, /* ml_linkage */ + NULL +}; + +/* + * Module entry points. + */ +int +_init(void) +{ + int error; + + neti_init(); + error = mod_install(&modlinkage); + if (error != 0) + neti_fini(); + + return (error); +} + + +int +_fini(void) +{ + int error; + + error = mod_remove(&modlinkage); + if (error == 0) + neti_fini(); + + return (error); +} + + +int +_info(struct modinfo *modinfop) +{ + + return (mod_info(&modlinkage, modinfop)); +} diff --git a/usr/src/uts/common/io/neti_stack.c b/usr/src/uts/common/io/neti_stack.c new file mode 100644 index 0000000000..1428638b7b --- /dev/null +++ b/usr/src/uts/common/io/neti_stack.c @@ -0,0 +1,840 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/param.h> +#include <sys/atomic.h> +#include <sys/kmem.h> +#include <sys/rwlock.h> +#include <sys/errno.h> +#include <sys/queue.h> +#include <sys/sunddi.h> +#include <inet/common.h> +#include <inet/led.h> +#include <inet/ip.h> +#include <sys/neti.h> +#include <sys/zone.h> +#include <sys/sdt.h> + + +typedef boolean_t napplyfn_t(kmutex_t *, neti_stack_t *, void *); + +static void *neti_stack_init(netstackid_t stackid, netstack_t *ns); +static void neti_stack_fini(netstackid_t stackid, void *arg); +static net_instance_int_t *net_instance_int_create(net_instance_t *nin, + net_instance_int_t *parent); +static void neti_stack_shutdown(netstackid_t stackid, void *arg); +static void net_instance_int_free(net_instance_int_t *nini); + +static boolean_t neti_stack_apply_create(kmutex_t *, neti_stack_t *, void *); +static boolean_t neti_stack_apply_destroy(kmutex_t *, neti_stack_t *, void *); +static boolean_t neti_stack_apply_shutdown(kmutex_t *, neti_stack_t *, void *); +static void neti_apply_all_instances(neti_stack_t *, napplyfn_t *); +static void neti_apply_all_stacks(void *, napplyfn_t *); +static boolean_t wait_for_nini_inprogress(neti_stack_t *, kmutex_t *, + net_instance_int_t *, uint32_t); + +static nini_head_t neti_instance_list; +static neti_stack_head_t neti_stack_list; +static kmutex_t neti_stack_lock; + +void +neti_init() +{ + mutex_init(&neti_stack_lock, NULL, MUTEX_DRIVER, NULL); + + LIST_INIT(&neti_instance_list); + LIST_INIT(&neti_stack_list); + /* + * We want to be informed each time a netstack is created or + * destroyed in the kernel. + */ + netstack_register(NS_NETI, neti_stack_init, neti_stack_shutdown, + neti_stack_fini); +} + +void +neti_fini() +{ + ASSERT(LIST_EMPTY(&neti_instance_list)); + ASSERT(LIST_EMPTY(&neti_stack_list)); + + netstack_unregister(NS_NETI); + + mutex_destroy(&neti_stack_lock); +} + +/* + * Initialize the neti stack instance. Because this is called out of the + * netstack framework, it is not possible for it to be called twice with + * the same values for (stackid,ns). The same also applies to the other + * two functions used with netstack_register: neti_stack_shutdown and + * neti_stack_fini. + */ +static void * +neti_stack_init(netstackid_t stackid, netstack_t *ns) +{ + net_instance_int_t *dup; + net_instance_int_t *n; + neti_stack_t *nts; + + nts = kmem_zalloc(sizeof (*nts), KM_SLEEP); + LIST_INIT(&nts->nts_instances); + nts->nts_id = (netid_t)stackid; + nts->nts_stackid = stackid; + nts->nts_netstack = ns; + nts->nts_zoneid = netstackid_to_zoneid(stackid); + nts->nts_flags = NSF_ZONE_CREATE; + cv_init(&nts->nts_cv, NULL, CV_DRIVER, NULL); + mutex_init(&nts->nts_lock, NULL, MUTEX_DRIVER, NULL); + + mutex_enter(&neti_stack_lock); + LIST_INSERT_HEAD(&neti_stack_list, nts, nts_next); + + LIST_FOREACH(n, &neti_instance_list, nini_next) { + /* + * This function returns with the NSS_CREATE_NEEDED flag + * set in "dup", so it is adequately prepared for the + * upcoming apply. + */ + dup = net_instance_int_create(n->nini_instance, n); + + mutex_enter(&nts->nts_lock); + LIST_INSERT_HEAD(&nts->nts_instances, dup, nini_next); + mutex_exit(&nts->nts_lock); + } + + neti_apply_all_instances(nts, neti_stack_apply_create); + + mutex_enter(&nts->nts_lock); + nts->nts_flags &= ~NSF_ZONE_CREATE; + cv_signal(&nts->nts_cv); + mutex_exit(&nts->nts_lock); + + mutex_exit(&neti_stack_lock); + + return (nts); +} + +/* + * Run the shutdown for all of the hooks. + */ +/*ARGSUSED*/ +static void +neti_stack_shutdown(netstackid_t stackid, void *arg) +{ + neti_stack_t *nts = arg; + net_instance_int_t *n; + struct net_data *nd; + + ASSERT(nts != NULL); + + mutex_enter(&neti_stack_lock); + mutex_enter(&nts->nts_lock); + /* + * Walk through all of the protocol stacks and mark them as shutting + * down. + */ + LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) { + nd->netd_condemned = 1; + } + + /* + * Now proceed to see which callbacks are waiting to hear about the + * impending shutdown... + */ + LIST_FOREACH(n, &nts->nts_instances, nini_next) { + if (n->nini_instance->nin_shutdown == NULL) { + /* + * If there is no shutdown function registered, + * fake that we have completed it. + */ + n->nini_flags |= NSS_SHUTDOWN_COMPLETED; + continue; + } + + /* + * We need to ensure that we don't try and shutdown something + * that is already in the process of being shutdown or + * destroyed. If it is still being created, that's ok, the + * shtudown flag is added to the mix of things to do. + */ + if ((n->nini_flags & (NSS_DESTROY_ALL|NSS_SHUTDOWN_ALL)) == 0) + n->nini_flags |= NSS_SHUTDOWN_NEEDED; + } + nts->nts_flags |= NSF_ZONE_SHUTDOWN; + mutex_exit(&nts->nts_lock); + + neti_apply_all_instances(nts, neti_stack_apply_shutdown); + + mutex_enter(&nts->nts_lock); + + nts->nts_netstack = NULL; + mutex_exit(&nts->nts_lock); + + mutex_exit(&neti_stack_lock); + ASSERT(nts != NULL); +} + +/* + * Free the neti stack instance. + * This function relies on the netstack framework only calling the _destroy + * callback once for each stackid. The netstack framework also provides us + * with assurance that nobody else will be doing any work (_create, _shutdown) + * on it, so there is no need to set and use flags to guard against + * simultaneous execution (ie. no need to set NSF_CLOSING.) + * What is required, however, is to make sure that we don't corrupt the + * list of neti_stack_t's for other code that walks it. + */ +/*ARGSUSED*/ +static void +neti_stack_fini(netstackid_t stackid, void *arg) +{ + neti_stack_t *nts = arg; + net_instance_int_t *n; + struct net_data *nd; + + mutex_enter(&neti_stack_lock); + LIST_REMOVE(nts, nts_next); + + mutex_enter(&nts->nts_lock); + nts->nts_flags |= NSF_ZONE_DESTROY; + /* + * Walk through all of the protocol stacks and mark them as being + * destroyed. + */ + LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) { + nd->netd_condemned = 2; + } + + LIST_FOREACH(n, &nts->nts_instances, nini_next) { + ASSERT((n->nini_flags & NSS_SHUTDOWN_ALL) != 0); + if (n->nini_instance->nin_shutdown == NULL) + continue; + if ((n->nini_flags & NSS_DESTROY_ALL) == 0) + n->nini_flags |= NSS_DESTROY_NEEDED; + } + mutex_exit(&nts->nts_lock); + + neti_apply_all_instances(nts, neti_stack_apply_destroy); + mutex_exit(&neti_stack_lock); + + while (!LIST_EMPTY(&nts->nts_instances)) { + n = LIST_FIRST(&nts->nts_instances); + LIST_REMOVE(n, nini_next); + + net_instance_int_free(n); + } + + ASSERT(LIST_EMPTY(&nts->nts_netd_head)); + + mutex_destroy(&nts->nts_lock); + cv_destroy(&nts->nts_cv); + + kmem_free(nts, sizeof (*nts)); +} + +static net_instance_int_t * +net_instance_int_create(net_instance_t *nin, net_instance_int_t *parent) +{ + net_instance_int_t *nini; + + nini = kmem_zalloc(sizeof (net_instance_int_t), KM_SLEEP); + nini->nini_instance = nin; + nini->nini_parent = parent; + if (parent != NULL) { + /* + * If the parent pointer is non-NULL then we take that as + * an indication that the net_instance_int_t is being + * created for an active instance and there will expect + * the create function to be called. In contrast, if + * parent is NULL then this code assumes the object is + * being prepared for insertion onto the master list of + * callbacks to be called when an instance is created, etc. + */ + parent->nini_ref++; + nini->nini_flags |= NSS_CREATE_NEEDED; + } + + cv_init(&nini->nini_cv, NULL, CV_DRIVER, NULL); + + return (nini); +} + +static void +net_instance_int_free(net_instance_int_t *nini) +{ + + cv_destroy(&nini->nini_cv); + + if (nini->nini_parent != NULL) + nini->nini_parent->nini_ref--; + + ASSERT(nini->nini_ref == 0); + kmem_free(nini, sizeof (*nini)); +} + +net_instance_t * +net_instance_alloc(const int version) +{ + net_instance_t *nin; + + if (version != NETINFO_VERSION) + return (NULL); + + nin = kmem_zalloc(sizeof (net_instance_t), KM_SLEEP); + nin->nin_version = version; + + return (nin); +} + +void +net_instance_free(net_instance_t *nin) +{ + kmem_free(nin, sizeof (*nin)); +} + +int +net_instance_register(net_instance_t *nin) +{ + net_instance_int_t *parent; + net_instance_int_t *tmp; + neti_stack_t *nts; + + ASSERT(nin->nin_name != NULL); + + if (nin->nin_create == NULL || nin->nin_destroy == NULL) + return (DDI_FAILURE); + + mutex_enter(&neti_stack_lock); + /* + * Search for duplicate, either on the global list or on any + * of the known instances. + */ + LIST_FOREACH(tmp, &neti_instance_list, nini_next) { + if (strcmp(nin->nin_name, tmp->nini_instance->nin_name) == 0) { + mutex_exit(&neti_stack_lock); + return (DDI_FAILURE); + } + } + + /* + * Now insert and activate. + */ + parent = net_instance_int_create(nin, NULL); + ASSERT(parent != NULL); + LIST_INSERT_HEAD(&neti_instance_list, parent, nini_next); + + LIST_FOREACH(nts, &neti_stack_list, nts_next) { + mutex_enter(&nts->nts_lock); + /* + * If shutdown of the zone has begun then do not add a new + * instance of the object being registered. + */ + if ((nts->nts_flags & NSF_ZONE_SHUTDOWN) || + (nts->nts_netstack == NULL)) { + mutex_exit(&nts->nts_lock); + continue; + } + /* + * This function returns with the NSS_CREATE_NEEDED flag + * set in "dup", so it is adequately prepared for the + * upcoming apply. + */ + tmp = net_instance_int_create(nin, parent); + ASSERT(tmp != NULL); + LIST_INSERT_HEAD(&nts->nts_instances, tmp, nini_next); + mutex_exit(&nts->nts_lock); + + } + + neti_apply_all_stacks(parent, neti_stack_apply_create); + mutex_exit(&neti_stack_lock); + + return (DDI_SUCCESS); +} + +/* + * While net_instance_register() isn't likely to be racing against itself, + * net_instance_unregister() can be entered from various directions that + * can compete: shutdown of a zone, unloading of a module (and it calling + * _unregister() as part of that) and the module doing an _unregister() + * anyway. + */ +int +net_instance_unregister(net_instance_t *nin) +{ + net_instance_int_t *parent; + net_instance_int_t *tmp; + neti_stack_t *nts; + + mutex_enter(&neti_stack_lock); + + LIST_FOREACH(tmp, &neti_instance_list, nini_next) { + if (strcmp(tmp->nini_instance->nin_name, nin->nin_name) == 0) { + LIST_REMOVE(tmp, nini_next); + break; + } + } + + if (tmp == NULL) { + mutex_exit(&neti_stack_lock); + return (DDI_FAILURE); + } + parent = tmp; + + LIST_FOREACH(nts, &neti_stack_list, nts_next) { + mutex_enter(&nts->nts_lock); + LIST_FOREACH(tmp, &nts->nts_instances, nini_next) { + if (tmp->nini_parent != parent) + continue; + /* + * Netstack difference: + * In netstack.c, there is a check for + * NSS_CREATE_COMPLETED before setting the other + * _NEEDED flags. If we consider that a list + * member must always have at least the _CREATE_NEEDED + * flag set and that wait_for_nini_inprogress will + * also wait for that flag to be cleared in both of + * the shutdown and destroy apply functions. + * + * It is possible to optimize out the case where + * all three _NEEDED flags are set to being able + * to pretend everything has been done and just + * set all three _COMPLETE flags. This makes a + * special case that we then need to consider in + * other locations, so for the sake of simplicity, + * we leave it as it is. + */ + if ((tmp->nini_flags & NSS_SHUTDOWN_ALL) == 0) + tmp->nini_flags |= NSS_SHUTDOWN_NEEDED; + if ((tmp->nini_flags & NSS_DESTROY_ALL) == 0) + tmp->nini_flags |= NSS_DESTROY_NEEDED; + } + mutex_exit(&nts->nts_lock); + } + + /* + * Each of these functions ensures that the requisite _COMPLETED + * flag is present before calling the apply function. So we are + * guaranteed to have NSS_CREATE_COMPLETED|NSS_SHUTDOWN_COMPLETED + * both set after the first call here and when the second completes, + * NSS_DESTROY_COMPLETED is also set. + */ + neti_apply_all_stacks(parent, neti_stack_apply_shutdown); + neti_apply_all_stacks(parent, neti_stack_apply_destroy); + + /* + * Remove the instance callback information from each stack. + */ + LIST_FOREACH(nts, &neti_stack_list, nts_next) { + mutex_enter(&nts->nts_lock); + LIST_FOREACH(tmp, &nts->nts_instances, nini_next) { + if ((tmp->nini_parent == parent) && + (tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) && + (tmp->nini_flags & NSS_DESTROY_COMPLETED)) { + /* + * There should only be one entry that has a + * matching nini_parent so there is no need to + * worry about continuing a loop where we are + * free'ing the structure holding the 'next' + * pointer. + */ + LIST_REMOVE(tmp, nini_next); + net_instance_int_free(tmp); + break; + } + } + mutex_exit(&nts->nts_lock); + } + mutex_exit(&neti_stack_lock); + + net_instance_int_free(parent); + + return (DDI_SUCCESS); +} + +static void +neti_apply_all_instances(neti_stack_t *nts, napplyfn_t *applyfn) +{ + net_instance_int_t *n; + + ASSERT(mutex_owned(&neti_stack_lock)); + + n = LIST_FIRST(&nts->nts_instances); + while (n != NULL) { + if ((applyfn)(&neti_stack_lock, nts, n->nini_parent)) { + /* Lock dropped - restart at head */ + n = LIST_FIRST(&nts->nts_instances); + } else { + n = LIST_NEXT(n, nini_next); + } + } +} + +static void +neti_apply_all_stacks(void *parent, napplyfn_t *applyfn) +{ + neti_stack_t *nts; + + ASSERT(mutex_owned(&neti_stack_lock)); + + nts = LIST_FIRST(&neti_stack_list); + while (nts != NULL) { + /* + * This function differs, in that it doesn't have a call to + * a "wait_creator" call, from the zsd/netstack code. The + * waiting is pushed into the apply functions which cause + * the waiting to be done in wait_for_nini_progress with + * the passing in of cmask. + */ + if ((applyfn)(&neti_stack_lock, nts, parent)) { + /* Lock dropped - restart at head */ + nts = LIST_FIRST(&neti_stack_list); + } else { + nts = LIST_NEXT(nts, nts_next); + } + } +} + +static boolean_t +neti_stack_apply_create(kmutex_t *lockp, neti_stack_t *nts, void *parent) +{ + void *result; + boolean_t dropped = B_FALSE; + net_instance_int_t *tmp; + net_instance_t *nin; + + ASSERT(parent != NULL); + ASSERT(lockp != NULL); + ASSERT(mutex_owned(lockp)); + + mutex_enter(&nts->nts_lock); + + LIST_FOREACH(tmp, &nts->nts_instances, nini_next) { + if (tmp->nini_parent == parent) + break; + } + if (tmp == NULL) { + mutex_exit(&nts->nts_lock); + return (dropped); + } + + if (wait_for_nini_inprogress(nts, lockp, tmp, 0)) + dropped = B_TRUE; + + if (tmp->nini_flags & NSS_CREATE_NEEDED) { + nin = tmp->nini_instance; + tmp->nini_flags &= ~NSS_CREATE_NEEDED; + tmp->nini_flags |= NSS_CREATE_INPROGRESS; + DTRACE_PROBE2(neti__stack__create__inprogress, + neti_stack_t *, nts, net_instance_int_t *, tmp); + mutex_exit(&nts->nts_lock); + mutex_exit(lockp); + dropped = B_TRUE; + + ASSERT(tmp->nini_created == NULL); + ASSERT(nin->nin_create != NULL); + DTRACE_PROBE2(neti__stack__create__start, + netstackid_t, nts->nts_id, + neti_stack_t *, nts); + result = (nin->nin_create)(nts->nts_id); + DTRACE_PROBE2(neti__stack__create__end, + void *, result, neti_stack_t *, nts); + + ASSERT(result != NULL); + mutex_enter(lockp); + mutex_enter(&nts->nts_lock); + tmp->nini_created = result; + tmp->nini_flags &= ~NSS_CREATE_INPROGRESS; + tmp->nini_flags |= NSS_CREATE_COMPLETED; + cv_broadcast(&tmp->nini_cv); + DTRACE_PROBE2(neti__stack__create__completed, + neti_stack_t *, nts, net_instance_int_t *, tmp); + } + mutex_exit(&nts->nts_lock); + return (dropped); +} + + +static boolean_t +neti_stack_apply_shutdown(kmutex_t *lockp, neti_stack_t *nts, void *parent) +{ + boolean_t dropped = B_FALSE; + net_instance_int_t *tmp; + net_instance_t *nin; + + ASSERT(parent != NULL); + ASSERT(lockp != NULL); + ASSERT(mutex_owned(lockp)); + + mutex_enter(&nts->nts_lock); + + LIST_FOREACH(tmp, &nts->nts_instances, nini_next) { + if (tmp->nini_parent == parent) + break; + } + if (tmp == NULL) { + mutex_exit(&nts->nts_lock); + return (dropped); + } + + if (wait_for_nini_inprogress(nts, lockp, tmp, NSS_CREATE_NEEDED)) + dropped = B_TRUE; + + nin = tmp->nini_instance; + if (nin->nin_shutdown == NULL) { + /* + * If there is no shutdown function, fake having completed it. + */ + if (tmp->nini_flags & NSS_SHUTDOWN_NEEDED) { + tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED; + tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED; + } + + mutex_exit(&nts->nts_lock); + return (dropped); + } + + if (tmp->nini_flags & NSS_SHUTDOWN_NEEDED) { + ASSERT((tmp->nini_flags & NSS_CREATE_COMPLETED) != 0); + tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED; + tmp->nini_flags |= NSS_SHUTDOWN_INPROGRESS; + DTRACE_PROBE2(neti__stack__shutdown__inprogress, + neti_stack_t *, nts, net_instance_int_t *, tmp); + mutex_exit(&nts->nts_lock); + mutex_exit(lockp); + dropped = B_TRUE; + + ASSERT(nin->nin_shutdown != NULL); + DTRACE_PROBE2(neti__stack__shutdown__start, + netstackid_t, nts->nts_id, + neti_stack_t *, nts); + (nin->nin_shutdown)(nts->nts_id, tmp->nini_created); + DTRACE_PROBE1(neti__stack__shutdown__end, + neti_stack_t *, nts); + + mutex_enter(lockp); + mutex_enter(&nts->nts_lock); + tmp->nini_flags &= ~NSS_SHUTDOWN_INPROGRESS; + tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED; + cv_broadcast(&tmp->nini_cv); + DTRACE_PROBE2(neti__stack__shutdown__completed, + neti_stack_t *, nts, net_instance_int_t *, tmp); + } + ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0); + mutex_exit(&nts->nts_lock); + return (dropped); +} + +static boolean_t +neti_stack_apply_destroy(kmutex_t *lockp, neti_stack_t *nts, void *parent) +{ + boolean_t dropped = B_FALSE; + net_instance_int_t *tmp; + net_instance_t *nin; + + ASSERT(parent != NULL); + ASSERT(lockp != NULL); + ASSERT(mutex_owned(lockp)); + + mutex_enter(&nts->nts_lock); + + LIST_FOREACH(tmp, &nts->nts_instances, nini_next) { + if (tmp->nini_parent == parent) + break; + } + if (tmp == NULL) { + mutex_exit(&nts->nts_lock); + return (dropped); + } + + /* + * We pause here so that when we continue we know that we're the + * only one doing anything active with this node. + */ + if (wait_for_nini_inprogress(nts, lockp, tmp, + NSS_CREATE_NEEDED|NSS_SHUTDOWN_NEEDED)) + dropped = B_TRUE; + + if (tmp->nini_flags & NSS_DESTROY_NEEDED) { + ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0); + nin = tmp->nini_instance; + tmp->nini_flags &= ~NSS_DESTROY_NEEDED; + tmp->nini_flags |= NSS_DESTROY_INPROGRESS; + DTRACE_PROBE2(neti__stack__destroy__inprogress, + neti_stack_t *, nts, net_instance_int_t *, tmp); + mutex_exit(&nts->nts_lock); + mutex_exit(lockp); + dropped = B_TRUE; + + ASSERT(nin->nin_destroy != NULL); + DTRACE_PROBE2(neti__stack__destroy__start, + netstackid_t, nts->nts_id, + neti_stack_t *, nts); + (nin->nin_destroy)(nts->nts_id, tmp->nini_created); + DTRACE_PROBE1(neti__stack__destroy__end, + neti_stack_t *, nts); + + mutex_enter(lockp); + mutex_enter(&nts->nts_lock); + tmp->nini_flags &= ~NSS_DESTROY_INPROGRESS; + tmp->nini_flags |= NSS_DESTROY_COMPLETED; + cv_broadcast(&tmp->nini_cv); + DTRACE_PROBE2(neti__stack__destroy__completed, + neti_stack_t *, nts, net_instance_int_t *, tmp); + } + mutex_exit(&nts->nts_lock); + return (dropped); +} + +static boolean_t +wait_for_nini_inprogress(neti_stack_t *nts, kmutex_t *lockp, + net_instance_int_t *nini, uint32_t cmask) +{ + boolean_t dropped = B_FALSE; + + ASSERT(lockp != NULL); + ASSERT(mutex_owned(lockp)); + + while (nini->nini_flags & (NSS_ALL_INPROGRESS|cmask)) { + DTRACE_PROBE2(netstack__wait__nms__inprogress, + neti_stack_t *, nts, net_instance_int_t *, nini); + dropped = B_TRUE; + mutex_exit(lockp); + + cv_wait(&nini->nini_cv, &nts->nts_lock); + + /* First drop netstack_lock to preserve order */ + mutex_exit(&nts->nts_lock); + mutex_enter(lockp); + mutex_enter(&nts->nts_lock); + } + return (dropped); +} + +/* ======================================================================= */ + +netid_t +net_zoneidtonetid(zoneid_t zoneid) +{ + + neti_stack_t *nts; + + mutex_enter(&neti_stack_lock); + LIST_FOREACH(nts, &neti_stack_list, nts_next) { + if (nts->nts_zoneid == zoneid) { + mutex_exit(&neti_stack_lock); + return (nts->nts_id); + } + } + mutex_exit(&neti_stack_lock); + + return (-1); +} + +zoneid_t +net_getzoneidbynetid(netid_t netid) +{ + neti_stack_t *nts; + + mutex_enter(&neti_stack_lock); + LIST_FOREACH(nts, &neti_stack_list, nts_next) { + if (nts->nts_id == netid) { + mutex_exit(&neti_stack_lock); + return (nts->nts_zoneid); + } + } + mutex_exit(&neti_stack_lock); + + return (-1); +} + +netstackid_t +net_getnetstackidbynetid(netid_t netid) +{ + neti_stack_t *nts; + + mutex_enter(&neti_stack_lock); + LIST_FOREACH(nts, &neti_stack_list, nts_next) { + if (nts->nts_id == netid) { + mutex_exit(&neti_stack_lock); + return (nts->nts_stackid); + } + } + mutex_exit(&neti_stack_lock); + + return (-1); +} + +netid_t +net_getnetidbynetstackid(netstackid_t netstackid) +{ + neti_stack_t *nts; + + mutex_enter(&neti_stack_lock); + LIST_FOREACH(nts, &neti_stack_list, nts_next) { + if (nts->nts_stackid == netstackid) { + mutex_exit(&neti_stack_lock); + return (nts->nts_id); + } + } + mutex_exit(&neti_stack_lock); + + return (-1); +} + +neti_stack_t * +net_getnetistackbyid(netid_t netid) +{ + neti_stack_t *nts; + + mutex_enter(&neti_stack_lock); + LIST_FOREACH(nts, &neti_stack_list, nts_next) { + if (nts->nts_id == netid) { + mutex_exit(&neti_stack_lock); + return (nts); + } + } + mutex_exit(&neti_stack_lock); + + return (NULL); +} + +int +net_instance_notify_register(netid_t netid, hook_notify_fn_t callback, + void *arg) +{ + + return (hook_stack_notify_register(net_getnetstackidbynetid(netid), + callback, arg)); +} + +int +net_instance_notify_unregister(netid_t netid, hook_notify_fn_t callback) +{ + + return (hook_stack_notify_unregister(net_getnetstackidbynetid(netid), + callback)); +} diff --git a/usr/src/uts/common/os/netstack.c b/usr/src/uts/common/os/netstack.c index c1e59fe6c3..37f851df8e 100644 --- a/usr/src/uts/common/os/netstack.c +++ b/usr/src/uts/common/os/netstack.c @@ -24,8 +24,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/param.h> #include <sys/sysmacros.h> #include <sys/vm.h> @@ -435,7 +433,7 @@ netstack_zone_shutdown(zoneid_t zoneid, void *arg) * Call the shutdown function for all registered modules for this * netstack. */ - apply_all_modules(ns, netstack_apply_shutdown); + apply_all_modules_reverse(ns, netstack_apply_shutdown); /* Tell any waiting netstack_register/netstack_unregister to proceed */ mutex_enter(&ns->netstack_lock); @@ -546,7 +544,7 @@ netstack_stack_inactive(netstack_t *ns) * leave nms_flags the way it is i.e. with NSS_DESTROY_COMPLETED set. * That is different than in the netstack_unregister() case. */ - apply_all_modules(ns, netstack_apply_shutdown); + apply_all_modules_reverse(ns, netstack_apply_shutdown); apply_all_modules_reverse(ns, netstack_apply_destroy); /* Tell any waiting netstack_register/netstack_unregister to proceed */ @@ -676,6 +674,7 @@ netstack_apply_create(kmutex_t *lockp, netstack_t *ns, int moduleid) DTRACE_PROBE2(netstack__create__start, netstackid_t, stackid, netstack_t *, ns); +printf("ns[%d](%d).create\n", moduleid, stackid); result = (ns_reg[moduleid].nr_create)(stackid, ns); DTRACE_PROBE2(netstack__create__end, void *, result, netstack_t *, ns); @@ -737,6 +736,7 @@ netstack_apply_shutdown(kmutex_t *lockp, netstack_t *ns, int moduleid) DTRACE_PROBE2(netstack__shutdown__start, netstackid_t, stackid, void *, netstack_module); +printf("ns[%d](%d).shutdown\n", moduleid, stackid); (ns_reg[moduleid].nr_shutdown)(stackid, netstack_module); DTRACE_PROBE1(netstack__shutdown__end, netstack_t *, ns); @@ -796,6 +796,7 @@ netstack_apply_destroy(kmutex_t *lockp, netstack_t *ns, int moduleid) DTRACE_PROBE2(netstack__destroy__start, netstackid_t, stackid, void *, netstack_module); +printf("ns[%d](%d).destroy\n", moduleid, stackid); (ns_reg[moduleid].nr_destroy)(stackid, netstack_module); DTRACE_PROBE1(netstack__destroy__end, netstack_t *, ns); diff --git a/usr/src/uts/common/sys/condvar_impl.h b/usr/src/uts/common/sys/condvar_impl.h index 75c5867375..429eede4f9 100644 --- a/usr/src/uts/common/sys/condvar_impl.h +++ b/usr/src/uts/common/sys/condvar_impl.h @@ -20,15 +20,13 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_CONDVAR_IMPL_H #define _SYS_CONDVAR_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Implementation-private definitions for condition variables */ @@ -102,6 +100,14 @@ typedef struct cvwaitlock_s { mutex_exit(&(_c)->cvw_lock); \ } +#define CVW_WRITE_TO_READ(_c) { \ + mutex_enter(&(_c)->cvw_lock); \ + ASSERT((_c)->cvw_refcnt == -1); \ + (_c)->cvw_refcnt = 1; \ + cv_broadcast(&(_c)->cvw_waiter); \ + mutex_exit(&(_c)->cvw_lock); \ +} + #define CVW_DESTROY(_c) { \ mutex_destroy(&(_c)->cvw_lock); \ cv_destroy(&(_c)->cvw_waiter); \ diff --git a/usr/src/uts/common/sys/hook.h b/usr/src/uts/common/sys/hook.h index 00b0048093..464f2b8b50 100644 --- a/usr/src/uts/common/sys/hook.h +++ b/usr/src/uts/common/sys/hook.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,8 +30,6 @@ #ifndef _SYS_HOOK_H #define _SYS_HOOK_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/queue.h> #include <sys/netstack.h> @@ -49,33 +47,62 @@ typedef uintptr_t hook_data_t; struct hook_event_int; typedef struct hook_event_int *hook_event_token_t; +struct hook_int; +typedef struct hook_int *hook_token_t; + +typedef int (* hook_func_t)(hook_event_token_t, hook_data_t, void *); + +/* + * A hook_notify_cmd_t is given as an argument to functions called as part of + * the notify callbacks that have been registered firing. + */ +typedef enum hook_notify_cmd_e { + HN_NONE = 0, + HN_REGISTER = 1, + HN_UNREGISTER = 2 +} hook_notify_cmd_t; -typedef int (* hook_func_t)(hook_event_token_t, hook_data_t, netstack_t *); +/* + * + */ +typedef enum hook_hint_e { + HH_NONE = 0, + HH_FIRST, + HH_LAST, + HH_BEFORE, + HH_AFTER +} hook_hint_t; /* * Hook */ -typedef struct hook { - int32_t h_version; /* version number */ +typedef struct hook_s { + int h_version; hook_func_t h_func; /* callback func */ char *h_name; /* name of this hook */ - int h_flags; /* extra hook properties */ + uint_t h_flags; /* extra hook properties */ + hook_hint_t h_hint; /* What type of hint is hintvalue */ + uintptr_t h_hintvalue; + void *h_arg; /* value to pass back into the hook */ } hook_t; -#define HOOK_INIT(x, fn, r) \ +#define HOOK_INIT(x, fn, r, a) \ do { \ - (x)->h_version = HOOK_VERSION; \ + (x) = hook_alloc(HOOK_VERSION); \ (x)->h_func = (fn); \ (x)->h_name = (r); \ (x)->h_flags = 0; \ + (x)->h_hint = HH_NONE; \ + (x)->h_hintvalue = 0; \ + (x)->h_arg = (a); \ _NOTE(CONSTCOND) \ } while (0) /* * Family */ -typedef struct hook_family { - int32_t hf_version; /* version number */ +typedef struct hook_family_s { + int hf_version; /* version number */ char *hf_name; /* family name */ } hook_family_t; @@ -89,8 +116,8 @@ typedef struct hook_family { /* * Event */ -typedef struct hook_event { - int32_t he_version; /* version number */ +typedef struct hook_event_s { + int he_version; char *he_name; /* name of this hook list */ int he_flags; /* 1 = multiple entries allowed */ boolean_t he_interested; /* true if callback exist */ @@ -108,6 +135,12 @@ typedef struct hook_event { _NOTE(CONSTCOND) \ } while (0) +typedef int (* hook_notify_fn_t)(hook_notify_cmd_t, void *, const char *, + const char *, const char *); + +extern hook_t *hook_alloc(const int version); +extern void hook_free(hook_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/hook_event.h b/usr/src/uts/common/sys/hook_event.h index 12dcef0e84..df99a67956 100644 --- a/usr/src/uts/common/sys/hook_event.h +++ b/usr/src/uts/common/sys/hook_event.h @@ -32,8 +32,6 @@ #ifndef _SYS_HOOK_EVENT_H #define _SYS_HOOK_EVENT_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/neti.h> #include <sys/hook.h> @@ -46,6 +44,8 @@ extern "C" { * associated network interfaces. * * The members of this structure are defined as follows: + * hpe_protocol - protocol identifier that indicates which protocol the + * header data is associated with. * hpe_ifp - "in" interface for packets coming into the system or forwarded * hpe_ofp - "out" interface for packets being transmitted or forwarded * hpe_hdr - pointer to protocol header within the packet @@ -53,12 +53,14 @@ extern "C" { * hpe_mb - pointer to the mblk that contains hpe_hdr */ typedef struct hook_pkt_event { + net_handle_t hpe_protocol; phy_if_t hpe_ifp; phy_if_t hpe_ofp; void *hpe_hdr; mblk_t **hpe_mp; mblk_t *hpe_mb; int hpe_flags; + void *hpe_reserved[2]; } hook_pkt_event_t; #define HPE_MULTICAST 0x01 @@ -81,7 +83,7 @@ typedef void *nic_event_data_t; * The hook_nic_event data structure is provided with all network interface * events. * - * hne_family - network family of events, returned from net_lookup + * hne_protocol- network protocol for events, returned from net_lookup * hne_nic - physical interface associated with event * hne_lif - logical interface (if any) associated with event * hne_event - type of event occuring @@ -89,7 +91,7 @@ typedef void *nic_event_data_t; * hne_datalen - size of data pointed to by hne_data (can be 0) */ typedef struct hook_nic_event { - net_data_t hne_family; + net_handle_t hne_protocol; phy_if_t hne_nic; lif_if_t hne_lif; nic_event_t hne_event; @@ -97,6 +99,15 @@ typedef struct hook_nic_event { size_t hne_datalen; } hook_nic_event_t; +/* + * This structure is used internally by ip to queue events. + */ +struct hook_nic_event_int { + netstackid_t hnei_stackid; + hook_nic_event_t hnei_event; +}; +typedef struct hook_nic_event_int hook_nic_event_int_t; + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/hook_impl.h b/usr/src/uts/common/sys/hook_impl.h index 08112e4144..2357a2d287 100644 --- a/usr/src/uts/common/sys/hook_impl.h +++ b/usr/src/uts/common/sys/hook_impl.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,8 +30,6 @@ #ifndef _SYS_HOOK_IMPL_H #define _SYS_HOOK_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/hook.h> #include <sys/condvar_impl.h> #include <sys/netstack.h> @@ -40,6 +38,31 @@ extern "C" { #endif +typedef enum fwflag_e { + FWF_NONE = 0x00, + FWF_DESTROY_ACTIVE = 0x01, + FWF_ADD_ACTIVE = 0x04, + FWF_DEL_ACTIVE = 0x08, + FWF_DESTROY_WANTED = 0x10, + FWF_ADD_WANTED = 0x40, + FWF_DEL_WANTED = 0x80, + FWF_NOT_READY = 0x100 +} fwflag_t; + +#define FWF_WAIT_MASK (FWF_ADD_ACTIVE|FWF_DEL_ACTIVE|\ + FWF_ADD_WANTED|FWF_DEL_WANTED) +#define FWF_UNSAFE (FWF_DESTROY_ACTIVE|FWF_NOT_READY) +#define FWF_DESTROY (FWF_DESTROY_ACTIVE|FWF_DESTROY_WANTED) +#define FWF_DESTROY_OK(x) ((x)->fw_flags == FWF_DESTROY_WANTED) + +typedef struct flagwait_s { + kcondvar_t fw_cv; + kmutex_t fw_lock; + uint32_t fw_flags; + cvwaitlock_t *fw_owner; +} flagwait_t; + + /* * The following diagram describes the linking together of data structures * used in this implementation of callback hooks. The start of it all is @@ -58,32 +81,66 @@ extern "C" { * | hook_family_int_t | / | hook_event_int_t | | / | hook_int_t | * | +---------------+ | / | | / / | +----------+ | * | | hook_family_t | | / | hei_event---------/ / | | hook_t | | - * | +---------------+ | / | | / | +----------+ | - * | | / | | / | | - * | hfi_head------------/ | hei_head-----------/ | hi_entry--\ | - * | hfi_entry--\ | | hei_entry--\ | +-----------|--+ - * +------------|------+ +------------|-----+ | - * | | | - * V V V - * +-------------------+ +------------------+ +--------------+ - * | hook_family_int_t | | hook_event_int_t | | hook_int_t | + * | +---------------+ | / | hei_nhead----------\ / | +----------+ | + * | | / | | X | | + * | hfi_head------------/ | hei_head-----------/ \ | hi_entry--\ | + * | hfi_entry--\ | | hei_entry--\ | | +-----------|--+ + * +------------|------+ +------------|-----+ | | + * | | | | + * V V | V + * +-------------------+ +------------------+ | +--------------+ + * | hook_family_int_t | | hook_event_int_t | | | hook_int_t | + * V + * +--------------+ + * | * ... */ +typedef struct hook_hook_kstat { + kstat_named_t hook_version; + kstat_named_t hook_flags; + kstat_named_t hook_hint; + kstat_named_t hook_hintvalue; + kstat_named_t hook_position; + kstat_named_t hook_hits; +} hook_hook_kstat_t; + /* * hook_int: internal storage of hook */ typedef struct hook_int { - TAILQ_ENTRY(hook_int) hi_entry; - hook_t hi_hook; + TAILQ_ENTRY(hook_int) hi_entry; + hook_t hi_hook; + hook_hook_kstat_t hi_kstats; + kstat_t *hi_kstatp; + char *hi_ksname; + cvwaitlock_t hi_notify_lock; } hook_int_t; /* - * Hook_int_head: tail queue of hook_int + * hook_int_head: tail queue of hook_int */ TAILQ_HEAD(hook_int_head, hook_int); typedef struct hook_int_head hook_int_head_t; + +typedef struct hook_notify { + TAILQ_ENTRY(hook_notify) hn_entry; + hook_notify_fn_t hn_func; + void *hn_arg; + uint32_t hn_flags; +} hook_notify_t; + +TAILQ_HEAD(hook_notify_head, hook_notify); +typedef struct hook_notify_head hook_notify_head_t; + + +typedef struct hook_event_kstat { + kstat_named_t hooks_added; + kstat_named_t hooks_removed; + kstat_named_t events; +} hook_event_kstat_t; + /* * hook_event_int: internal storage of hook_event */ @@ -92,6 +149,11 @@ typedef struct hook_event_int { SLIST_ENTRY(hook_event_int) hei_entry; hook_event_t *hei_event; hook_int_head_t hei_head; + kstat_t *hei_kstatp; + hook_event_kstat_t hei_kstats; + hook_notify_head_t hei_nhead; + flagwait_t hei_waiter; + boolean_t hei_condemned; } hook_event_int_t; /* @@ -104,10 +166,15 @@ typedef struct hook_event_int_head hook_event_int_head_t; * hook_family_int: internal storage of hook_family */ typedef struct hook_family_int { + cvwaitlock_t hfi_lock; SLIST_ENTRY(hook_family_int) hfi_entry; hook_event_int_head_t hfi_head; hook_family_t hfi_family; - void *hfi_ptr; + kstat_t *hfi_kstat; + struct hook_stack *hfi_stack; + hook_notify_head_t hfi_nhead; + flagwait_t hfi_waiter; + boolean_t hfi_condemned; } hook_family_int_t; /* @@ -120,11 +187,18 @@ typedef struct hook_family_int_head hook_family_int_head_t; * hook stack instances */ struct hook_stack { - cvwaitlock_t hks_familylock; /* global lock */ - hook_family_int_head_t hks_familylist; /* family list head */ - netstack_t *hk_netstack; + cvwaitlock_t hks_lock; + SLIST_ENTRY(hook_stack) hks_entry; + hook_family_int_head_t hks_familylist; /* family list head */ + netstack_t *hks_netstack; + netstackid_t hks_netstackid; + hook_notify_head_t hks_nhead; + int hks_shutdown; + flagwait_t hks_waiter; }; typedef struct hook_stack hook_stack_t; +SLIST_HEAD(hook_stack_head, hook_stack); +typedef struct hook_stack_head hook_stack_head_t; /* * Names of hooks families currently defined by Solaris @@ -133,13 +207,26 @@ typedef struct hook_stack hook_stack_t; #define Hn_IPV4 "inet" #define Hn_IPV6 "inet6" -extern hook_family_int_t *hook_family_add(hook_family_t *, hook_stack_t *); -extern int hook_family_remove(hook_family_int_t *); -extern hook_event_int_t *hook_event_add(hook_family_int_t *, hook_event_t *); -extern int hook_event_remove(hook_family_int_t *, hook_event_t *); +extern int hook_run(hook_family_int_t *, hook_event_token_t, hook_data_t); extern int hook_register(hook_family_int_t *, char *, hook_t *); + extern int hook_unregister(hook_family_int_t *, char *, hook_t *); -extern int hook_run(hook_event_token_t, hook_data_t, netstack_t *); +extern hook_event_int_t *hook_event_add(hook_family_int_t *, hook_event_t *); +extern int hook_event_notify_register(hook_family_int_t *, char *, + hook_notify_fn_t, void *); +extern int hook_event_notify_unregister(hook_family_int_t *, char *, + hook_notify_fn_t); +extern int hook_event_remove(hook_family_int_t *, hook_event_t *); + +extern hook_family_int_t *hook_family_add(hook_family_t *, hook_stack_t *); +extern int hook_family_notify_register(hook_family_int_t *, hook_notify_fn_t, + void *); +extern int hook_family_notify_unregister(hook_family_int_t *, hook_notify_fn_t); +extern int hook_family_remove(hook_family_int_t *); + +extern int hook_stack_notify_register(netstackid_t, hook_notify_fn_t, void *); +extern int hook_stack_notify_unregister(netstackid_t, hook_notify_fn_t); + #ifdef __cplusplus } diff --git a/usr/src/uts/common/sys/neti.h b/usr/src/uts/common/sys/neti.h index ea6c843158..ad82ae0d87 100644 --- a/usr/src/uts/common/sys/neti.h +++ b/usr/src/uts/common/sys/neti.h @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_NETI_H #define _SYS_NETI_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <netinet/in.h> #include <sys/int_types.h> #include <sys/queue.h> @@ -81,9 +79,7 @@ extern "C" { typedef uintptr_t phy_if_t; typedef intptr_t lif_if_t; typedef uintptr_t net_ifdata_t; - -struct net_data; -typedef struct net_data *net_data_t; +typedef id_t netid_t; /* * Netinfo interface specification @@ -106,33 +102,41 @@ typedef enum inject { NI_DIRECT_OUT } inject_t; +/* + * net_inject - public interface + */ typedef struct net_inject { + int ni_version; + netid_t ni_netid; mblk_t *ni_packet; struct sockaddr_storage ni_addr; phy_if_t ni_physical; } net_inject_t; +typedef struct net_data *net_handle_t; /* - * net_info_t public interface + * net_protocol_t private interface */ -typedef struct net_info { - int neti_version; - char *neti_protocol; - int (*neti_getifname)(phy_if_t, char *, const size_t, - netstack_t *); - int (*neti_getmtu)(phy_if_t, lif_if_t, netstack_t *); - int (*neti_getpmtuenabled)(netstack_t *); - int (*neti_getlifaddr)(phy_if_t, lif_if_t, size_t, - net_ifaddr_t [], void *, netstack_t *); - phy_if_t (*neti_phygetnext)(phy_if_t, netstack_t *); - phy_if_t (*neti_phylookup)(const char *, netstack_t *); - lif_if_t (*neti_lifgetnext)(phy_if_t, lif_if_t, netstack_t *); - int (*neti_inject)(inject_t, net_inject_t *, netstack_t *); - phy_if_t (*neti_routeto)(struct sockaddr *, netstack_t *); - int (*neti_ispartialchecksum)(mblk_t *); - int (*neti_isvalidchecksum)(mblk_t *); -} net_info_t; +struct net_protocol_s { + int netp_version; + char *netp_name; + int (*netp_getifname)(net_handle_t, phy_if_t, char *, + const size_t); + int (*netp_getmtu)(net_handle_t, phy_if_t, lif_if_t); + int (*netp_getpmtuenabled)(net_handle_t); + int (*netp_getlifaddr)(net_handle_t, phy_if_t, lif_if_t, + size_t, net_ifaddr_t [], void *); + phy_if_t (*netp_phygetnext)(net_handle_t, phy_if_t); + phy_if_t (*netp_phylookup)(net_handle_t, const char *); + lif_if_t (*netp_lifgetnext)(net_handle_t, phy_if_t, lif_if_t); + int (*netp_inject)(net_handle_t, inject_t, net_inject_t *); + phy_if_t (*netp_routeto)(net_handle_t, struct sockaddr *, + struct sockaddr *); + int (*netp_ispartialchecksum)(net_handle_t, mblk_t *); + int (*netp_isvalidchecksum)(net_handle_t, mblk_t *); +}; +typedef struct net_protocol_s net_protocol_t; /* @@ -140,10 +144,11 @@ typedef struct net_info { */ struct net_data { LIST_ENTRY(net_data) netd_list; - net_info_t netd_info; + net_protocol_t netd_info; int netd_refcnt; hook_family_int_t *netd_hooks; - netstack_t *netd_netstack; + struct neti_stack_s *netd_stack; + int netd_condemned; }; @@ -162,53 +167,117 @@ typedef struct injection_s { #define MAP_IPIF_ID(x) ((x) + 1) #define UNMAP_IPIF_ID(x) (((x) > 0) ? (x) - 1 : (x)) +struct net_instance_s { + int nin_version; + char *nin_name; + void *(*nin_create)(const netid_t); + void (*nin_destroy)(const netid_t, void *); + void (*nin_shutdown)(const netid_t, void *); +}; +typedef struct net_instance_s net_instance_t; + +struct net_instance_int_s { + LIST_ENTRY(net_instance_int_s) nini_next; + int nini_ref; + void *nini_created; + struct net_instance_int_s *nini_parent; + net_instance_t *nini_instance; + hook_notify_t nini_notify; + uint32_t nini_flags; + kcondvar_t nini_cv; +}; +typedef struct net_instance_int_s net_instance_int_t; +LIST_HEAD(nini_head_s, net_instance_int_s); +typedef struct nini_head_s nini_head_t; + +#define nini_version nini_instance->nin_version +#define nini_name nini_instance->nin_name +#define nini_create nini_instance->nin_create +#define nini_destroy nini_instance->nin_destroy +#define nini_shutdown nini_instance->nin_shutdown /* - * neti stack instances + * netinfo stack instances */ -struct neti_stack { - krwlock_t nts_netlock; - - /* list of net_data_t */ +struct neti_stack_s { + kmutex_t nts_lock; + LIST_ENTRY(neti_stack_s) nts_next; + netid_t nts_id; + zoneid_t nts_zoneid; + netstackid_t nts_stackid; + netstack_t *nts_netstack; + nini_head_t nts_instances; + uint32_t nts_flags; + kcondvar_t nts_cv; + /* list of net_handle_t */ LIST_HEAD(netd_listhead, net_data) nts_netd_head; - netstack_t *nts_netstack; }; -typedef struct neti_stack neti_stack_t; - +typedef struct neti_stack_s neti_stack_t; +LIST_HEAD(neti_stack_head_s, neti_stack_s); +typedef struct neti_stack_head_s neti_stack_head_t; /* - * Data management functions + * Internal functions that need to be exported within the module. */ -extern net_data_t net_register(const net_info_t *, netstackid_t); -extern net_data_t net_register_impl(const net_info_t *, netstack_t *); -extern int net_unregister(net_data_t); -extern net_data_t net_lookup(const char *, netstackid_t); -extern net_data_t net_lookup_impl(const char *, netstack_t *); -extern int net_release(net_data_t); -extern net_data_t net_walk(net_data_t, netstackid_t); -extern net_data_t net_walk_impl(net_data_t, netstack_t *); +extern void neti_init(void); +extern void neti_fini(void); +extern neti_stack_t *net_getnetistackbyid(netid_t); +extern netstackid_t net_getnetstackidbynetid(netid_t); +extern netid_t net_getnetidbynetstackid(netstackid_t); +extern netid_t net_zoneidtonetid(zoneid_t); +extern zoneid_t net_getzoneidbynetid(netid_t); /* - * Accessor functions + * Functions available for public use. */ -extern int net_register_family(net_data_t, hook_family_t *); -extern int net_unregister_family(net_data_t, hook_family_t *); -extern hook_event_token_t net_register_event(net_data_t, hook_event_t *); -extern int net_unregister_event(net_data_t, hook_event_t *); -extern int net_register_hook(net_data_t, char *, hook_t *); -extern int net_unregister_hook(net_data_t, char *, hook_t *); -extern int net_getifname(net_data_t, phy_if_t, char *, const size_t); -extern int net_getmtu(net_data_t, phy_if_t, lif_if_t); -extern int net_getpmtuenabled(net_data_t); -extern int net_getlifaddr(net_data_t, phy_if_t, lif_if_t, +extern hook_event_token_t net_event_register(net_handle_t, hook_event_t *); +extern int net_event_unregister(net_handle_t, hook_event_t *); +extern int net_event_notify_register(net_handle_t, char *, + hook_notify_fn_t, void *); +extern int net_event_notify_unregister(net_handle_t, char *, hook_notify_fn_t); + +extern int net_family_register(net_handle_t, hook_family_t *); +extern int net_family_unregister(net_handle_t, hook_family_t *); + +extern int net_hook_register(net_handle_t, char *, hook_t *); +extern int net_hook_unregister(net_handle_t, char *, hook_t *); + +extern int net_inject(net_handle_t, inject_t, net_inject_t *); +extern net_inject_t *net_inject_alloc(const int); +extern void net_inject_free(net_inject_t *); + +extern net_instance_t *net_instance_alloc(const int version); +extern void net_instance_free(net_instance_t *); +extern int net_instance_register(net_instance_t *); +extern int net_instance_unregister(net_instance_t *); +extern int net_instance_notify_register(netid_t, hook_notify_fn_t, void *); +extern int net_instance_notify_unregister(netid_t netid, hook_notify_fn_t); + +extern kstat_t *net_kstat_create(netid_t, char *, int, char *, char *, + uchar_t, ulong_t, uchar_t); +extern void net_kstat_delete(netid_t, kstat_t *); + +extern net_handle_t net_protocol_lookup(netid_t, const char *); +extern net_handle_t net_protocol_register(netid_t, const net_protocol_t *); +extern int net_protocol_release(net_handle_t); +extern int net_protocol_unregister(net_handle_t); +extern net_handle_t net_protocol_walk(netid_t, net_handle_t); +extern int net_protocol_notify_register(net_handle_t, hook_notify_fn_t, void *); +extern int net_protocol_notify_unregister(net_handle_t, hook_notify_fn_t); + + +extern int net_getifname(net_handle_t, phy_if_t, char *, const size_t); +extern int net_getmtu(net_handle_t, phy_if_t, lif_if_t); +extern int net_getpmtuenabled(net_handle_t); +extern int net_getlifaddr(net_handle_t, phy_if_t, lif_if_t, int, net_ifaddr_t [], void *); -extern phy_if_t net_phygetnext(net_data_t, phy_if_t); -extern phy_if_t net_phylookup(net_data_t, const char *); -extern lif_if_t net_lifgetnext(net_data_t, phy_if_t, lif_if_t); -extern int net_inject(net_data_t, inject_t, net_inject_t *); -extern phy_if_t net_routeto(net_data_t, struct sockaddr *); -extern int net_ispartialchecksum(net_data_t, mblk_t *); -extern int net_isvalidchecksum(net_data_t, mblk_t *); +extern phy_if_t net_phygetnext(net_handle_t, phy_if_t); +extern phy_if_t net_phylookup(net_handle_t, const char *); +extern lif_if_t net_lifgetnext(net_handle_t, phy_if_t, lif_if_t); +extern phy_if_t net_routeto(net_handle_t, struct sockaddr *, + struct sockaddr *); +extern int net_ispartialchecksum(net_handle_t, mblk_t *); +extern int net_isvalidchecksum(net_handle_t, mblk_t *); #ifdef __cplusplus } diff --git a/usr/src/uts/common/sys/netstack.h b/usr/src/uts/common/sys/netstack.h index 9bd7701693..55acab834c 100644 --- a/usr/src/uts/common/sys/netstack.h +++ b/usr/src/uts/common/sys/netstack.h @@ -26,8 +26,6 @@ #ifndef _SYS_NETSTACK_H #define _SYS_NETSTACK_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/kstat.h> #ifdef __cplusplus @@ -64,24 +62,23 @@ typedef id_t netstackid_t; * done ine in decending order). */ #define NS_ALL -1 /* Match all */ -#define NS_HOOK 0 -#define NS_NETI 1 -#define NS_ARP 2 -#define NS_IP 3 -#define NS_ICMP 4 -#define NS_UDP 5 -#define NS_TCP 6 -#define NS_SCTP 7 -#define NS_RTS 8 -#define NS_IPSEC 9 -#define NS_KEYSOCK 10 -#define NS_SPDSOCK 11 -#define NS_IPSECAH 12 -#define NS_IPSECESP 13 -#define NS_TUN 14 -#define NS_IPF 15 -#define NS_STR 16 /* autopush list etc */ -#define NS_MAX (NS_STR+1) +#define NS_STR 0 /* autopush list etc */ +#define NS_HOOK 1 +#define NS_NETI 2 +#define NS_ARP 3 +#define NS_IP 4 +#define NS_ICMP 5 +#define NS_UDP 6 +#define NS_TCP 7 +#define NS_SCTP 8 +#define NS_RTS 9 +#define NS_IPSEC 10 +#define NS_KEYSOCK 11 +#define NS_SPDSOCK 12 +#define NS_IPSECAH 13 +#define NS_IPSECESP 14 +#define NS_TUN 15 +#define NS_MAX (NS_TUN+1) /* * State maintained for each module which tracks the state of @@ -138,6 +135,7 @@ struct netstack { union { void *nu_modules[NS_MAX]; struct { + struct str_stack *nu_str; struct hook_stack *nu_hook; struct neti_stack *nu_neti; struct arp_stack *nu_arp; @@ -153,11 +151,10 @@ struct netstack { struct ipsecah_stack *nu_ipsecah; struct ipsecesp_stack *nu_ipsecesp; struct tun_stack *nu_tun; - struct ipf_stack *nu_ipf; - struct str_stack *nu_str; } nu_s; } netstack_u; #define netstack_modules netstack_u.nu_modules +#define netstack_str netstack_u.nu_s.nu_str #define netstack_hook netstack_u.nu_s.nu_hook #define netstack_neti netstack_u.nu_s.nu_neti #define netstack_arp netstack_u.nu_s.nu_arp @@ -173,8 +170,6 @@ struct netstack { #define netstack_ipsecah netstack_u.nu_s.nu_ipsecah #define netstack_ipsecesp netstack_u.nu_s.nu_ipsecesp #define netstack_tun netstack_u.nu_s.nu_tun -#define netstack_ipf netstack_u.nu_s.nu_ipf -#define netstack_str netstack_u.nu_s.nu_str nm_state_t netstack_m_state[NS_MAX]; /* module state */ diff --git a/usr/src/uts/intel/hook/hook.global-objs.debug64 b/usr/src/uts/intel/hook/hook.global-objs.debug64 index c813224003..48d393076f 100644 --- a/usr/src/uts/intel/hook/hook.global-objs.debug64 +++ b/usr/src/uts/intel/hook/hook.global-objs.debug64 @@ -19,10 +19,11 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" modlinkage modlmisc +hook_stack_lock +hook_stacks diff --git a/usr/src/uts/intel/ipf/Makefile b/usr/src/uts/intel/ipf/Makefile index 8ae5ba3dff..db27bf34f7 100644 --- a/usr/src/uts/intel/ipf/Makefile +++ b/usr/src/uts/intel/ipf/Makefile @@ -22,8 +22,6 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" -# # uts/intel/ipf/Makefile # # This makefile drives the production of the ipf driver @@ -60,7 +58,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) CPPFLAGS += -DIPFILTER_LKM -DIPFILTER_LOG -DIPFILTER_LOOKUP -DUSE_INET6 CPPFLAGS += -DSUNDDI -DSOLARIS2=$(RELEASE_MINOR) -DIRE_ILL_CN -LDFLAGS += -dy -Ndrv/ip -Nmisc/md5 -Nmisc/neti -Nmisc/kcf +LDFLAGS += -dy -Ndrv/ip -Nmisc/md5 -Nmisc/neti -Nmisc/hook -Nmisc/kcf INC_PATH += -I$(UTSBASE)/common/inet/ipf diff --git a/usr/src/uts/intel/ipf/ipf.global-objs.debug64 b/usr/src/uts/intel/ipf/ipf.global-objs.debug64 index de4365bbd0..203dd14416 100644 --- a/usr/src/uts/intel/ipf/ipf.global-objs.debug64 +++ b/usr/src/uts/intel/ipf/ipf.global-objs.debug64 @@ -22,7 +22,6 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" fr_availfuncs fr_features @@ -40,7 +39,10 @@ ipf_devfiles ipf_kstat_tmp ipf_ops ipf_proxy_debug +ipf_stack_lock +ipf_stacks ipfilter_version +ipfncb ipl_magic iplmod ipopts diff --git a/usr/src/uts/intel/neti/neti.global-objs.debug64 b/usr/src/uts/intel/neti/neti.global-objs.debug64 index c813224003..f0ebce499b 100644 --- a/usr/src/uts/intel/neti/neti.global-objs.debug64 +++ b/usr/src/uts/intel/neti/neti.global-objs.debug64 @@ -19,10 +19,12 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" modlinkage modlmisc +neti_instance_list +neti_stack_list +neti_stack_lock diff --git a/usr/src/uts/sparc/hook/hook.global-objs.debug64 b/usr/src/uts/sparc/hook/hook.global-objs.debug64 index c813224003..48d393076f 100644 --- a/usr/src/uts/sparc/hook/hook.global-objs.debug64 +++ b/usr/src/uts/sparc/hook/hook.global-objs.debug64 @@ -19,10 +19,11 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" modlinkage modlmisc +hook_stack_lock +hook_stacks diff --git a/usr/src/uts/sparc/ipf/Makefile b/usr/src/uts/sparc/ipf/Makefile index 9ab95b305b..1270d808af 100644 --- a/usr/src/uts/sparc/ipf/Makefile +++ b/usr/src/uts/sparc/ipf/Makefile @@ -22,8 +22,6 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" -# # uts/sparc/ipf/Makefile # # @@ -65,7 +63,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) CFLAGS += $(CCVERBOSE) CPPFLAGS += -DIPFILTER_LKM -DIPFILTER_LOG -DIPFILTER_LOOKUP CPPFLAGS += -DSUNDDI -DSOLARIS2=$(RELEASE_MINOR) -DIRE_ILL_CN -DUSE_INET6 -LDFLAGS += -dy -Ndrv/ip -Nmisc/md5 -Nmisc/neti -Nmisc/kcf +LDFLAGS += -dy -Ndrv/ip -Nmisc/md5 -Nmisc/neti -Nmisc/hook -Nmisc/kcf INC_PATH += -I$(UTSBASE)/common/inet/ipf diff --git a/usr/src/uts/sparc/ipf/ipf.global-objs.debug64 b/usr/src/uts/sparc/ipf/ipf.global-objs.debug64 index 21c10a84f4..61566e8b65 100644 --- a/usr/src/uts/sparc/ipf/ipf.global-objs.debug64 +++ b/usr/src/uts/sparc/ipf/ipf.global-objs.debug64 @@ -22,7 +22,6 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" fr_availfuncs fr_features @@ -40,7 +39,10 @@ ipf_devfiles ipf_kstat_tmp ipf_ops ipf_proxy_debug +ipf_stack_lock +ipf_stacks ipfilter_version +ipfncb ipl_magic iplmod ipopts diff --git a/usr/src/uts/sparc/neti/Makefile b/usr/src/uts/sparc/neti/Makefile index 3a338bb130..2520b77173 100644 --- a/usr/src/uts/sparc/neti/Makefile +++ b/usr/src/uts/sparc/neti/Makefile @@ -21,11 +21,9 @@ # # uts/sparc/neti/Makefile # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" -# # This makefile drives the production of the neti driver kernel module. # # SPARC implementation architecture dependent diff --git a/usr/src/uts/sparc/neti/neti.global-objs.debug64 b/usr/src/uts/sparc/neti/neti.global-objs.debug64 index c813224003..f0ebce499b 100644 --- a/usr/src/uts/sparc/neti/neti.global-objs.debug64 +++ b/usr/src/uts/sparc/neti/neti.global-objs.debug64 @@ -19,10 +19,12 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" modlinkage modlmisc +neti_instance_list +neti_stack_list +neti_stack_lock |