xref: /onnv-gate/usr/src/uts/common/io/ib/clients/rds/rdssubr.c (revision 11042:2d6e217af1b4)
13302Sagiri /*
23302Sagiri  * CDDL HEADER START
33302Sagiri  *
43302Sagiri  * The contents of this file are subject to the terms of the
53302Sagiri  * Common Development and Distribution License (the "License").
63302Sagiri  * You may not use this file except in compliance with the License.
73302Sagiri  *
83302Sagiri  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93302Sagiri  * or http://www.opensolaris.org/os/licensing.
103302Sagiri  * See the License for the specific language governing permissions
113302Sagiri  * and limitations under the License.
123302Sagiri  *
133302Sagiri  * When distributing Covered Code, include this CDDL HEADER in each
143302Sagiri  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153302Sagiri  * If applicable, add the following below this CDDL HEADER, with the
163302Sagiri  * fields enclosed by brackets "[]" replaced with your own identifying
173302Sagiri  * information: Portions Copyright [yyyy] [name of copyright owner]
183302Sagiri  *
193302Sagiri  * CDDL HEADER END
203302Sagiri  */
213302Sagiri /*
22*11042SErik.Nordmark@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
233302Sagiri  * Use is subject to license terms.
243302Sagiri  */
253302Sagiri 
263302Sagiri #include <sys/ib/clients/rds/rds.h>
273302Sagiri #include <sys/ib/clients/rds/rds_kstat.h>
283302Sagiri 
293302Sagiri #include <inet/ipclassifier.h>
303302Sagiri 
313302Sagiri struct rds_kstat_s rds_kstat = {
323302Sagiri 	{"rds_nports",			KSTAT_DATA_ULONG},
333302Sagiri 	{"rds_nsessions",		KSTAT_DATA_ULONG},
343302Sagiri 	{"rds_tx_bytes",		KSTAT_DATA_ULONG},
353302Sagiri 	{"rds_tx_pkts",			KSTAT_DATA_ULONG},
363302Sagiri 	{"rds_tx_errors",		KSTAT_DATA_ULONG},
373302Sagiri 	{"rds_rx_bytes",		KSTAT_DATA_ULONG},
383302Sagiri 	{"rds_rx_pkts",			KSTAT_DATA_ULONG},
393302Sagiri 	{"rds_rx_pkts_pending",		KSTAT_DATA_ULONG},
403302Sagiri 	{"rds_rx_errors",		KSTAT_DATA_ULONG},
413302Sagiri 	{"rds_tx_acks",			KSTAT_DATA_ULONG},
423302Sagiri 	{"rds_post_recv_buf_called",	KSTAT_DATA_ULONG},
433302Sagiri 	{"rds_stalls_triggered",	KSTAT_DATA_ULONG},
443302Sagiri 	{"rds_stalls_sent",		KSTAT_DATA_ULONG},
453302Sagiri 	{"rds_unstalls_triggered",	KSTAT_DATA_ULONG},
463302Sagiri 	{"rds_unstalls_sent",		KSTAT_DATA_ULONG},
473302Sagiri 	{"rds_stalls_recvd",		KSTAT_DATA_ULONG},
483302Sagiri 	{"rds_unstalls_recvd",		KSTAT_DATA_ULONG},
493302Sagiri 	{"rds_stalls_ignored",		KSTAT_DATA_ULONG},
503302Sagiri 	{"rds_enobufs",			KSTAT_DATA_ULONG},
513302Sagiri 	{"rds_ewouldblocks",		KSTAT_DATA_ULONG},
523302Sagiri 	{"rds_failovers",		KSTAT_DATA_ULONG},
533302Sagiri 	{"rds_port_quota",		KSTAT_DATA_ULONG},
543302Sagiri 	{"rds_port_quota_adjusted",	KSTAT_DATA_ULONG},
553302Sagiri };
563302Sagiri 
573302Sagiri kstat_t *rds_kstatsp;
583302Sagiri static kmutex_t rds_kstat_mutex;
593302Sagiri 
603302Sagiri 
613302Sagiri struct	kmem_cache	*rds_alloc_cache;
623302Sagiri 
633302Sagiri uint_t	rds_bind_fanout_size = RDS_BIND_FANOUT_SIZE;
643302Sagiri rds_bf_t *rds_bind_fanout;
653302Sagiri 
663302Sagiri void
rds_increment_kstat(kstat_named_t * ksnp,boolean_t lock,uint_t num)673302Sagiri rds_increment_kstat(kstat_named_t *ksnp, boolean_t lock, uint_t num)
683302Sagiri {
693302Sagiri 	if (lock)
703302Sagiri 		mutex_enter(&rds_kstat_mutex);
713302Sagiri 	ksnp->value.ul += num;
723302Sagiri 	if (lock)
733302Sagiri 		mutex_exit(&rds_kstat_mutex);
743302Sagiri }
753302Sagiri 
763302Sagiri void
rds_decrement_kstat(kstat_named_t * ksnp,boolean_t lock,uint_t num)773302Sagiri rds_decrement_kstat(kstat_named_t *ksnp, boolean_t lock, uint_t num)
783302Sagiri {
793302Sagiri 	if (lock)
803302Sagiri 		mutex_enter(&rds_kstat_mutex);
813302Sagiri 	ksnp->value.ul -= num;
823302Sagiri 	if (lock)
833302Sagiri 		mutex_exit(&rds_kstat_mutex);
843302Sagiri }
853302Sagiri 
863302Sagiri void
rds_set_kstat(kstat_named_t * ksnp,boolean_t lock,ulong_t num)873302Sagiri rds_set_kstat(kstat_named_t *ksnp, boolean_t lock, ulong_t num)
883302Sagiri {
893302Sagiri 	if (lock)
903302Sagiri 		mutex_enter(&rds_kstat_mutex);
913302Sagiri 	ksnp->value.ul = num;
923302Sagiri 	if (lock)
933302Sagiri 		mutex_exit(&rds_kstat_mutex);
943302Sagiri }
953302Sagiri 
963302Sagiri ulong_t
rds_get_kstat(kstat_named_t * ksnp,boolean_t lock)973302Sagiri rds_get_kstat(kstat_named_t *ksnp, boolean_t lock)
983302Sagiri {
993302Sagiri 	ulong_t	value;
1003302Sagiri 
1013302Sagiri 	if (lock)
1023302Sagiri 		mutex_enter(&rds_kstat_mutex);
1033302Sagiri 	value = ksnp->value.ul;
1043302Sagiri 	if (lock)
1053302Sagiri 		mutex_exit(&rds_kstat_mutex);
1063302Sagiri 
1073302Sagiri 	return (value);
1083302Sagiri }
1093302Sagiri 
1103302Sagiri 
1113302Sagiri void
rds_fini()1123302Sagiri rds_fini()
1133302Sagiri {
1143302Sagiri 	int	i;
1153302Sagiri 
1163302Sagiri 	for (i = 0; i < rds_bind_fanout_size; i++) {
1173302Sagiri 		mutex_destroy(&rds_bind_fanout[i].rds_bf_lock);
1183302Sagiri 	}
1193302Sagiri 	kmem_free(rds_bind_fanout, rds_bind_fanout_size * sizeof (rds_bf_t));
1203302Sagiri 
1213302Sagiri 	kmem_cache_destroy(rds_alloc_cache);
1223302Sagiri 	kstat_delete(rds_kstatsp);
1233302Sagiri }
1243302Sagiri 
1253302Sagiri 
1263302Sagiri void
rds_init()1273302Sagiri rds_init()
1283302Sagiri {
1293302Sagiri 	rds_alloc_cache = kmem_cache_create("rds_alloc_cache",
1303302Sagiri 	    sizeof (rds_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
1313302Sagiri 	rds_hash_init();
1323302Sagiri 	/*
1333302Sagiri 	 * kstats
1343302Sagiri 	 */
1353302Sagiri 	rds_kstatsp = kstat_create("rds", 0,
136*11042SErik.Nordmark@Sun.COM 	    "rds_kstat", "misc", KSTAT_TYPE_NAMED,
137*11042SErik.Nordmark@Sun.COM 	    sizeof (rds_kstat) / sizeof (kstat_named_t),
138*11042SErik.Nordmark@Sun.COM 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
1393302Sagiri 	if (rds_kstatsp != NULL) {
1403302Sagiri 		rds_kstatsp->ks_lock = &rds_kstat_mutex;
1413302Sagiri 		rds_kstatsp->ks_data = (void *)&rds_kstat;
1423302Sagiri 		kstat_install(rds_kstatsp);
1433302Sagiri 	}
1443302Sagiri }
1453302Sagiri 
1463302Sagiri #define	UINT_32_BITS 31
1473302Sagiri void
rds_hash_init()1483302Sagiri rds_hash_init()
1493302Sagiri {
1503302Sagiri 	int i;
1513302Sagiri 
1523302Sagiri 	if (rds_bind_fanout_size & (rds_bind_fanout_size - 1)) {
1533302Sagiri 		/* Not a power of two. Round up to nearest power of two */
1543302Sagiri 		for (i = 0; i < UINT_32_BITS; i++) {
1553302Sagiri 			if (rds_bind_fanout_size < (1 << i))
1563302Sagiri 				break;
1573302Sagiri 		}
1583302Sagiri 		rds_bind_fanout_size = 1 << i;
1593302Sagiri 	}
1603302Sagiri 	rds_bind_fanout = kmem_zalloc(rds_bind_fanout_size *
1613302Sagiri 	    sizeof (rds_bf_t), KM_SLEEP);
1623302Sagiri 	for (i = 0; i < rds_bind_fanout_size; i++) {
1633302Sagiri 		mutex_init(&rds_bind_fanout[i].rds_bf_lock, NULL, MUTEX_DEFAULT,
1643302Sagiri 		    NULL);
1653302Sagiri 	}
1663302Sagiri }
1673302Sagiri 
1683302Sagiri void
rds_free(rds_t * rds)1693302Sagiri rds_free(rds_t *rds)
1703302Sagiri {
1713302Sagiri 	ASSERT(rds->rds_refcnt == 0);
1723302Sagiri 	ASSERT(MUTEX_HELD(&rds->rds_lock));
1733302Sagiri 	crfree(rds->rds_cred);
1743302Sagiri 	kmem_cache_free(rds_alloc_cache, rds);
1753302Sagiri }
1763302Sagiri 
1773302Sagiri rds_t *
rds_create(void * rds_ulpd,cred_t * credp)1783302Sagiri rds_create(void *rds_ulpd, cred_t *credp)
1793302Sagiri {
1803302Sagiri 	rds_t	*rds;
1813302Sagiri 
1823302Sagiri 	/* User must supply a credential. */
1833302Sagiri 	if (credp == NULL)
1843302Sagiri 		return (NULL);
1853302Sagiri 	rds = kmem_cache_alloc(rds_alloc_cache, KM_SLEEP);
1863302Sagiri 	if (rds == NULL) {
1873302Sagiri 		return (NULL);
1883302Sagiri 	}
1893302Sagiri 
1903302Sagiri 	bzero(rds, sizeof (rds_t));
1913302Sagiri 	mutex_init(&rds->rds_lock, NULL, MUTEX_DEFAULT, NULL);
1923302Sagiri 	cv_init(&rds->rds_refcv, NULL, CV_DEFAULT, NULL);
1933302Sagiri 	rds->rds_cred = credp;
1943302Sagiri 	rds->rds_ulpd = rds_ulpd;
1953302Sagiri 	rds->rds_zoneid = getzoneid();
1963302Sagiri 	crhold(credp);
1973302Sagiri 	rds->rds_refcnt++;
1983302Sagiri 	return (rds);
1993302Sagiri }
2003302Sagiri 
2013302Sagiri 
2023302Sagiri /*
2033302Sagiri  * Hash list removal routine for rds_t structures.
2043302Sagiri  */
2053302Sagiri void
rds_bind_hash_remove(rds_t * rds,boolean_t caller_holds_lock)2063302Sagiri rds_bind_hash_remove(rds_t *rds, boolean_t caller_holds_lock)
2073302Sagiri {
2083302Sagiri 	rds_t   *rdsnext;
2093302Sagiri 	kmutex_t *lockp;
2103302Sagiri 
2113302Sagiri 	if (rds->rds_ptpbhn == NULL)
2123302Sagiri 		return;
2133302Sagiri 
2143302Sagiri 	/*
2153302Sagiri 	 * Extract the lock pointer in case there are concurrent
2163302Sagiri 	 * hash_remove's for this instance.
2173302Sagiri 	 */
2183302Sagiri 	ASSERT(rds->rds_port != 0);
2193302Sagiri 	if (!caller_holds_lock) {
2203302Sagiri 		lockp = &rds_bind_fanout[RDS_BIND_HASH(rds->rds_port)].
2213302Sagiri 		    rds_bf_lock;
2223302Sagiri 		ASSERT(lockp != NULL);
2233302Sagiri 		mutex_enter(lockp);
2243302Sagiri 	}
2253302Sagiri 
2263302Sagiri 	if (rds->rds_ptpbhn != NULL) {
2273302Sagiri 		rdsnext = rds->rds_bind_hash;
2283302Sagiri 		if (rdsnext != NULL) {
2293302Sagiri 			rdsnext->rds_ptpbhn = rds->rds_ptpbhn;
2303302Sagiri 			rds->rds_bind_hash = NULL;
2313302Sagiri 		}
2323302Sagiri 		*rds->rds_ptpbhn = rdsnext;
2333302Sagiri 		rds->rds_ptpbhn = NULL;
2343302Sagiri 	}
2353302Sagiri 
2363302Sagiri 	RDS_DEC_REF_CNT(rds);
2373302Sagiri 
2383302Sagiri 	if (!caller_holds_lock) {
2393302Sagiri 		mutex_exit(lockp);
2403302Sagiri 	}
2413302Sagiri }
2423302Sagiri 
2433302Sagiri void
rds_bind_hash_insert(rds_bf_t * rdsbf,rds_t * rds)2443302Sagiri rds_bind_hash_insert(rds_bf_t *rdsbf, rds_t *rds)
2453302Sagiri {
2463302Sagiri 	rds_t   **rdsp;
2473302Sagiri 	rds_t   *rdsnext;
2483302Sagiri 
2493302Sagiri 	ASSERT(MUTEX_HELD(&rdsbf->rds_bf_lock));
2503302Sagiri 	if (rds->rds_ptpbhn != NULL) {
2513302Sagiri 		rds_bind_hash_remove(rds, B_TRUE);
2523302Sagiri 	}
2533302Sagiri 
2543302Sagiri 	rdsp = &rdsbf->rds_bf_rds;
2553302Sagiri 	rdsnext = rdsp[0];
2563302Sagiri 
2573302Sagiri 	if (rdsnext != NULL) {
2583302Sagiri 		rdsnext->rds_ptpbhn = &rds->rds_bind_hash;
2593302Sagiri 	}
2603302Sagiri 	rds->rds_bind_hash = rdsnext;
2613302Sagiri 	rds->rds_ptpbhn = rdsp;
2623302Sagiri 	rdsp[0] = rds;
2633302Sagiri 	RDS_INCR_REF_CNT(rds);
2643302Sagiri 
2653302Sagiri }
2663302Sagiri 
2673302Sagiri /*
2683302Sagiri  * Everything is in network byte order
2693302Sagiri  */
2703302Sagiri /* ARGSUSED */
2713302Sagiri rds_t *
rds_fanout(ipaddr_t local_addr,ipaddr_t rem_addr,in_port_t local_port,in_port_t rem_port,zoneid_t zoneid)2723302Sagiri rds_fanout(ipaddr_t local_addr, ipaddr_t rem_addr,
2733302Sagiri     in_port_t local_port, in_port_t rem_port, zoneid_t zoneid)
2743302Sagiri {
2753302Sagiri 	rds_t	*rds;
2763302Sagiri 	rds_bf_t *rdsbf;
2773302Sagiri 
2783302Sagiri 	rdsbf = &rds_bind_fanout[RDS_BIND_HASH(local_port)];
2793302Sagiri 	mutex_enter(&rdsbf->rds_bf_lock);
2803302Sagiri 	rds = rdsbf->rds_bf_rds;
2813302Sagiri 	while (rds != NULL) {
2823302Sagiri 		if (!(rds->rds_flags & RDS_CLOSING)) {
2833302Sagiri 			if ((RDS_MATCH(rds, local_port, local_addr)) &&
2843302Sagiri 			    ((local_addr != INADDR_LOOPBACK) ||
2853302Sagiri 			    (rds->rds_zoneid == zoneid))) {
2863302Sagiri 				RDS_INCR_REF_CNT(rds);
2873302Sagiri 				break;
2883302Sagiri 			}
2893302Sagiri 		}
2903302Sagiri 		rds = rds->rds_bind_hash;
2913302Sagiri 	}
2923302Sagiri 	mutex_exit(&rdsbf->rds_bf_lock);
2933302Sagiri 	return (rds);
2943302Sagiri }
2953302Sagiri 
2963302Sagiri boolean_t
rds_islocal(ipaddr_t addr)2973302Sagiri rds_islocal(ipaddr_t addr)
2983302Sagiri {
2993448Sdh155122 	ip_stack_t *ipst;
3003448Sdh155122 
3013448Sdh155122 	ipst = netstack_find_by_zoneid(GLOBAL_ZONEID)->netstack_ip;
3023448Sdh155122 	ASSERT(ipst != NULL);
303*11042SErik.Nordmark@Sun.COM 	if (ip_laddr_verify_v4(addr, ALL_ZONES, ipst, B_FALSE) == IPVL_BAD) {
304*11042SErik.Nordmark@Sun.COM 		netstack_rele(ipst->ips_netstack);
305*11042SErik.Nordmark@Sun.COM 		return (B_FALSE);
306*11042SErik.Nordmark@Sun.COM 	}
3073448Sdh155122 	netstack_rele(ipst->ips_netstack);
3083302Sagiri 	return (B_TRUE);
3093302Sagiri }
310