diff options
author | Rishi Srivatsavai <Rishi.Srivatsavai@Sun.COM> | 2009-08-31 14:40:17 -0400 |
---|---|---|
committer | Rishi Srivatsavai <Rishi.Srivatsavai@Sun.COM> | 2009-08-31 14:40:17 -0400 |
commit | 0f83d385c54b2d67790eb5ee77344de60f0966c8 (patch) | |
tree | 07ab9a574badb34f7e983458b2f778cbdd92e940 /usr/src | |
parent | 5a7d610ecbaaaefcbf27334c5f4d503d32f4c767 (diff) | |
download | illumos-joyent-0f83d385c54b2d67790eb5ee77344de60f0966c8.tar.gz |
6876228 simnets usage with several bridge instances causes kernel stack overflow
6851752 simnet in dladm usage text should be removed
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/dladm/dladm.c | 12 | ||||
-rw-r--r-- | usr/src/uts/common/io/simnet/simnet.c | 110 |
2 files changed, 78 insertions, 44 deletions
diff --git a/usr/src/cmd/dladm/dladm.c b/usr/src/cmd/dladm/dladm.c index c20685154b..58e5dd2b8a 100644 --- a/usr/src/cmd/dladm/dladm.c +++ b/usr/src/cmd/dladm/dladm.c @@ -285,14 +285,10 @@ static cmd_t cmds[] = { " delete-etherstub [-t] <link>" }, { "show-etherstub", do_show_etherstub, " show-etherstub [-t] [<link>]\n" }, - { "create-simnet", do_create_simnet, - " create-simnet [-t] [-m <media>] <link>" }, - { "modify-simnet", do_modify_simnet, - " modify-simnet [-t] [-p <peer>] <link>" }, - { "delete-simnet", do_delete_simnet, - " delete-simnet [-t] <link>" }, - { "show-simnet", do_show_simnet, - " show-simnet [-pP] [-o <field>,...] [<link>]\n" }, + { "create-simnet", do_create_simnet, NULL }, + { "modify-simnet", do_modify_simnet, NULL }, + { "delete-simnet", do_delete_simnet, NULL }, + { "show-simnet", do_show_simnet, NULL }, { "up-simnet", do_up_simnet, NULL }, { "show-usage", do_show_usage, " show-usage [-a] [-d | -F <format>] " diff --git a/usr/src/uts/common/io/simnet/simnet.c b/usr/src/uts/common/io/simnet/simnet.c index 0c138ae445..2654538d02 100644 --- a/usr/src/uts/common/io/simnet/simnet.c +++ b/usr/src/uts/common/io/simnet/simnet.c @@ -54,12 +54,14 @@ #include <inet/wifi_ioctl.h> #include <sys/thread.h> #include <sys/synch.h> +#include <sys/sunddi.h> #include "simnet_impl.h" #define SIMNETINFO "Simulated Network Driver" static dev_info_t *simnet_dip; +static ddi_taskq_t *simnet_rxq; static int simnet_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); static int simnet_attach(dev_info_t *, ddi_attach_cmd_t); @@ -166,13 +168,16 @@ _info(struct modinfo *modinfop) return (mod_info(&modlinkage, modinfop)); } -static void +static boolean_t simnet_init(void) { + if ((simnet_rxq = ddi_taskq_create(simnet_dip, "simnet", 1, + TASKQ_DEFAULTPRI, 0)) == NULL) + return (B_FALSE); rw_init(&simnet_dev_lock, NULL, RW_DEFAULT, NULL); list_create(&simnet_dev_list, sizeof (simnet_dev_t), offsetof(simnet_dev_t, sd_listnode)); - simnet_count = 0; + return (B_TRUE); } static void @@ -181,6 +186,7 @@ simnet_fini(void) ASSERT(simnet_count == 0); rw_destroy(&simnet_dev_lock); list_destroy(&simnet_dev_list); + ddi_taskq_destroy(simnet_rxq); } /*ARGSUSED*/ @@ -208,12 +214,14 @@ simnet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) /* we only allow instance 0 to attach */ return (DDI_FAILURE); } + if (dld_ioc_register(SIMNET_IOC, simnet_ioc_list, DLDIOCCNT(simnet_ioc_list)) != 0) return (DDI_FAILURE); simnet_dip = dip; - simnet_init(); + if (!simnet_init()) + return (DDI_FAILURE); return (DDI_SUCCESS); case DDI_RESUME: @@ -237,9 +245,9 @@ simnet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) if (simnet_count > 0) return (DDI_FAILURE); - simnet_dip = NULL; - simnet_fini(); dld_ioc_unregister(SIMNET_IOC); + simnet_fini(); + simnet_dip = NULL; return (DDI_SUCCESS); case DDI_SUSPEND: @@ -256,6 +264,7 @@ simnet_dev_lookup(datalink_id_t link_id) { simnet_dev_t *sdev; + ASSERT(RW_LOCK_HELD(&simnet_dev_lock)); for (sdev = list_head(&simnet_dev_list); sdev != NULL; sdev = list_next(&simnet_dev_list, sdev)) { if (!(sdev->sd_flags & SDF_SHUTDOWN) && @@ -436,6 +445,7 @@ simnet_remove_peer(simnet_dev_t *sdev) simnet_dev_t *sdev_peer; datalink_id_t peer_link_id = DATALINK_INVALID_LINKID; + ASSERT(RW_WRITE_HELD(&simnet_dev_lock)); if ((sdev_peer = sdev->sd_peer_dev) != NULL) { ASSERT(sdev == sdev_peer->sd_peer_dev); sdev_peer->sd_peer_dev = NULL; @@ -607,16 +617,44 @@ simnet_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) return (0); } +static boolean_t +simnet_thread_ref(simnet_dev_t *sdev) +{ + mutex_enter(&sdev->sd_instlock); + if (sdev->sd_flags & SDF_SHUTDOWN || + !(sdev->sd_flags & SDF_STARTED)) { + mutex_exit(&sdev->sd_instlock); + return (B_FALSE); + } + sdev->sd_threadcount++; + mutex_exit(&sdev->sd_instlock); + return (B_TRUE); +} + static void -simnet_rx(simnet_dev_t *sdev, mblk_t *mp) +simnet_thread_unref(simnet_dev_t *sdev) { + mutex_enter(&sdev->sd_instlock); + if (--sdev->sd_threadcount == 0) + cv_broadcast(&sdev->sd_threadwait); + mutex_exit(&sdev->sd_instlock); +} + +static void +simnet_rx(void *arg) +{ + mblk_t *mp = arg; mac_header_info_t hdr_info; + simnet_dev_t *sdev; + + sdev = (simnet_dev_t *)mp->b_next; + mp->b_next = NULL; /* Check for valid packet header */ if (mac_header_info(sdev->sd_mh, mp, &hdr_info) != 0) { freemsg(mp); sdev->sd_stats.recv_errors++; - return; + goto rx_done; } /* @@ -630,14 +668,14 @@ simnet_rx(simnet_dev_t *sdev, mblk_t *mp) bcmp(hdr_info.mhi_daddr, sdev->sd_mac_addr, ETHERADDRL) != 0) { freemsg(mp); - return; + goto rx_done; } else if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) { mutex_enter(&sdev->sd_instlock); if (mcastaddr_lookup(sdev, hdr_info.mhi_daddr) == NULL) { mutex_exit(&sdev->sd_instlock); freemsg(mp); - return; + goto rx_done; } mutex_exit(&sdev->sd_instlock); } @@ -646,6 +684,8 @@ simnet_rx(simnet_dev_t *sdev, mblk_t *mp) sdev->sd_stats.recv_count++; sdev->sd_stats.rbytes += msgdsize(mp); mac_rx(sdev->sd_mh, NULL, mp); +rx_done: + simnet_thread_unref(sdev); } static mblk_t * @@ -675,31 +715,18 @@ simnet_m_tx(void *arg, mblk_t *mp_chain) * (reader lock) and increment the threadcount of the peer, the peer * MAC cannot be disabled in simnet_ioc_delete. */ - mutex_enter(&sdev_rx->sd_instlock); - if (sdev_rx->sd_flags & SDF_SHUTDOWN || - !(sdev_rx->sd_flags & SDF_STARTED)) { - mutex_exit(&sdev_rx->sd_instlock); + if (!simnet_thread_ref(sdev_rx)) { rw_exit(&simnet_dev_lock); freemsgchain(mp_chain); return (NULL); } - sdev_rx->sd_threadcount++; - mutex_exit(&sdev_rx->sd_instlock); rw_exit(&simnet_dev_lock); - mutex_enter(&sdev->sd_instlock); - if (sdev->sd_flags & SDF_SHUTDOWN || - !(sdev->sd_flags & SDF_STARTED)) { - mutex_exit(&sdev->sd_instlock); - mutex_enter(&sdev_rx->sd_instlock); - if (--sdev_rx->sd_threadcount == 0) - cv_broadcast(&sdev_rx->sd_threadwait); - mutex_exit(&sdev_rx->sd_instlock); + if (!simnet_thread_ref(sdev)) { + simnet_thread_unref(sdev_rx); freemsgchain(mp_chain); return (NULL); } - sdev->sd_threadcount++; - mutex_exit(&sdev->sd_instlock); while ((mp = mpnext) != NULL) { int len; @@ -743,19 +770,29 @@ simnet_m_tx(void *arg, mblk_t *mp_chain) continue; } - sdev->sd_stats.xmit_count++; - sdev->sd_stats.obytes += len; - simnet_rx(sdev_rx, mp); + /* Hold reference for taskq receive processing per-pkt */ + if (!simnet_thread_ref(sdev_rx)) { + freemsg(mp); + freemsgchain(mpnext); + break; + } + + /* Use taskq for pkt receive to avoid kernel stack explosion */ + mp->b_next = (mblk_t *)sdev_rx; + if (ddi_taskq_dispatch(simnet_rxq, simnet_rx, mp, + DDI_NOSLEEP) == DDI_SUCCESS) { + sdev->sd_stats.xmit_count++; + sdev->sd_stats.obytes += len; + } else { + simnet_thread_unref(sdev_rx); + mp->b_next = NULL; + freemsg(mp); + sdev_rx->sd_stats.recv_errors++; + } } - mutex_enter(&sdev->sd_instlock); - if (--sdev->sd_threadcount == 0) - cv_broadcast(&sdev->sd_threadwait); - mutex_exit(&sdev->sd_instlock); - mutex_enter(&sdev_rx->sd_instlock); - if (--sdev_rx->sd_threadcount == 0) - cv_broadcast(&sdev_rx->sd_threadwait); - mutex_exit(&sdev_rx->sd_instlock); + simnet_thread_unref(sdev); + simnet_thread_unref(sdev_rx); return (NULL); } @@ -920,6 +957,7 @@ mcastaddr_lookup(simnet_dev_t *sdev, const uint8_t *addrp) int idx; uint8_t *maddrptr; + ASSERT(MUTEX_HELD(&sdev->sd_instlock)); maddrptr = sdev->sd_mcastaddrs; for (idx = 0; idx < sdev->sd_mcastaddr_count; idx++) { if (bcmp(maddrptr, addrp, ETHERADDRL) == 0) |