1b86efd96Sagiri /*
2b86efd96Sagiri  * CDDL HEADER START
3b86efd96Sagiri  *
4b86efd96Sagiri  * The contents of this file are subject to the terms of the
5b86efd96Sagiri  * Common Development and Distribution License (the "License").
6b86efd96Sagiri  * You may not use this file except in compliance with the License.
7b86efd96Sagiri  *
8b86efd96Sagiri  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9b86efd96Sagiri  * or http://www.opensolaris.org/os/licensing.
10b86efd96Sagiri  * See the License for the specific language governing permissions
11b86efd96Sagiri  * and limitations under the License.
12b86efd96Sagiri  *
13b86efd96Sagiri  * When distributing Covered Code, include this CDDL HEADER in each
14b86efd96Sagiri  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15b86efd96Sagiri  * If applicable, add the following below this CDDL HEADER, with the
16b86efd96Sagiri  * fields enclosed by brackets "[]" replaced with your own identifying
17b86efd96Sagiri  * information: Portions Copyright [yyyy] [name of copyright owner]
18b86efd96Sagiri  *
19b86efd96Sagiri  * CDDL HEADER END
20b86efd96Sagiri  */
21b86efd96Sagiri /*
22bd670b35SErik Nordmark  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23b86efd96Sagiri  * Use is subject to license terms.
24b86efd96Sagiri  */
25b86efd96Sagiri 
26*de710d24SJosef 'Jeff' Sipek #include <sys/sysmacros.h>
27b86efd96Sagiri #include <sys/ib/clients/rds/rds.h>
28b86efd96Sagiri #include <sys/ib/clients/rds/rds_kstat.h>
29b86efd96Sagiri 
30b86efd96Sagiri #include <inet/ipclassifier.h>
31b86efd96Sagiri 
32b86efd96Sagiri struct rds_kstat_s rds_kstat = {
33b86efd96Sagiri 	{"rds_nports",			KSTAT_DATA_ULONG},
34b86efd96Sagiri 	{"rds_nsessions",		KSTAT_DATA_ULONG},
35b86efd96Sagiri 	{"rds_tx_bytes",		KSTAT_DATA_ULONG},
36b86efd96Sagiri 	{"rds_tx_pkts",			KSTAT_DATA_ULONG},
37b86efd96Sagiri 	{"rds_tx_errors",		KSTAT_DATA_ULONG},
38b86efd96Sagiri 	{"rds_rx_bytes",		KSTAT_DATA_ULONG},
39b86efd96Sagiri 	{"rds_rx_pkts",			KSTAT_DATA_ULONG},
40b86efd96Sagiri 	{"rds_rx_pkts_pending",		KSTAT_DATA_ULONG},
41b86efd96Sagiri 	{"rds_rx_errors",		KSTAT_DATA_ULONG},
42b86efd96Sagiri 	{"rds_tx_acks",			KSTAT_DATA_ULONG},
43b86efd96Sagiri 	{"rds_post_recv_buf_called",	KSTAT_DATA_ULONG},
44b86efd96Sagiri 	{"rds_stalls_triggered",	KSTAT_DATA_ULONG},
45b86efd96Sagiri 	{"rds_stalls_sent",		KSTAT_DATA_ULONG},
46b86efd96Sagiri 	{"rds_unstalls_triggered",	KSTAT_DATA_ULONG},
47b86efd96Sagiri 	{"rds_unstalls_sent",		KSTAT_DATA_ULONG},
48b86efd96Sagiri 	{"rds_stalls_recvd",		KSTAT_DATA_ULONG},
49b86efd96Sagiri 	{"rds_unstalls_recvd",		KSTAT_DATA_ULONG},
50b86efd96Sagiri 	{"rds_stalls_ignored",		KSTAT_DATA_ULONG},
51b86efd96Sagiri 	{"rds_enobufs",			KSTAT_DATA_ULONG},
52b86efd96Sagiri 	{"rds_ewouldblocks",		KSTAT_DATA_ULONG},
53b86efd96Sagiri 	{"rds_failovers",		KSTAT_DATA_ULONG},
54b86efd96Sagiri 	{"rds_port_quota",		KSTAT_DATA_ULONG},
55b86efd96Sagiri 	{"rds_port_quota_adjusted",	KSTAT_DATA_ULONG},
56b86efd96Sagiri };
57b86efd96Sagiri 
58b86efd96Sagiri kstat_t *rds_kstatsp;
59b86efd96Sagiri static kmutex_t rds_kstat_mutex;
60b86efd96Sagiri 
61b86efd96Sagiri 
62b86efd96Sagiri struct	kmem_cache	*rds_alloc_cache;
63b86efd96Sagiri 
64b86efd96Sagiri uint_t	rds_bind_fanout_size = RDS_BIND_FANOUT_SIZE;
65b86efd96Sagiri rds_bf_t *rds_bind_fanout;
66b86efd96Sagiri 
67b86efd96Sagiri void
rds_increment_kstat(kstat_named_t * ksnp,boolean_t lock,uint_t num)68b86efd96Sagiri rds_increment_kstat(kstat_named_t *ksnp, boolean_t lock, uint_t num)
69b86efd96Sagiri {
70b86efd96Sagiri 	if (lock)
71b86efd96Sagiri 		mutex_enter(&rds_kstat_mutex);
72b86efd96Sagiri 	ksnp->value.ul += num;
73b86efd96Sagiri 	if (lock)
74b86efd96Sagiri 		mutex_exit(&rds_kstat_mutex);
75b86efd96Sagiri }
76b86efd96Sagiri 
77b86efd96Sagiri void
rds_decrement_kstat(kstat_named_t * ksnp,boolean_t lock,uint_t num)78b86efd96Sagiri rds_decrement_kstat(kstat_named_t *ksnp, boolean_t lock, uint_t num)
79b86efd96Sagiri {
80b86efd96Sagiri 	if (lock)
81b86efd96Sagiri 		mutex_enter(&rds_kstat_mutex);
82b86efd96Sagiri 	ksnp->value.ul -= num;
83b86efd96Sagiri 	if (lock)
84b86efd96Sagiri 		mutex_exit(&rds_kstat_mutex);
85b86efd96Sagiri }
86b86efd96Sagiri 
87b86efd96Sagiri void
rds_set_kstat(kstat_named_t * ksnp,boolean_t lock,ulong_t num)88b86efd96Sagiri rds_set_kstat(kstat_named_t *ksnp, boolean_t lock, ulong_t num)
89b86efd96Sagiri {
90b86efd96Sagiri 	if (lock)
91b86efd96Sagiri 		mutex_enter(&rds_kstat_mutex);
92b86efd96Sagiri 	ksnp->value.ul = num;
93b86efd96Sagiri 	if (lock)
94b86efd96Sagiri 		mutex_exit(&rds_kstat_mutex);
95b86efd96Sagiri }
96b86efd96Sagiri 
97b86efd96Sagiri ulong_t
rds_get_kstat(kstat_named_t * ksnp,boolean_t lock)98b86efd96Sagiri rds_get_kstat(kstat_named_t *ksnp, boolean_t lock)
99b86efd96Sagiri {
100b86efd96Sagiri 	ulong_t	value;
101b86efd96Sagiri 
102b86efd96Sagiri 	if (lock)
103b86efd96Sagiri 		mutex_enter(&rds_kstat_mutex);
104b86efd96Sagiri 	value = ksnp->value.ul;
105b86efd96Sagiri 	if (lock)
106b86efd96Sagiri 		mutex_exit(&rds_kstat_mutex);
107b86efd96Sagiri 
108b86efd96Sagiri 	return (value);
109b86efd96Sagiri }
110b86efd96Sagiri 
111b86efd96Sagiri 
112b86efd96Sagiri void
rds_fini()113b86efd96Sagiri rds_fini()
114b86efd96Sagiri {
115b86efd96Sagiri 	int	i;
116b86efd96Sagiri 
117b86efd96Sagiri 	for (i = 0; i < rds_bind_fanout_size; i++) {
118b86efd96Sagiri 		mutex_destroy(&rds_bind_fanout[i].rds_bf_lock);
119b86efd96Sagiri 	}
120b86efd96Sagiri 	kmem_free(rds_bind_fanout, rds_bind_fanout_size * sizeof (rds_bf_t));
121b86efd96Sagiri 
122b86efd96Sagiri 	kmem_cache_destroy(rds_alloc_cache);
123b86efd96Sagiri 	kstat_delete(rds_kstatsp);
124b86efd96Sagiri }
125b86efd96Sagiri 
126b86efd96Sagiri 
127b86efd96Sagiri void
rds_init()128b86efd96Sagiri rds_init()
129b86efd96Sagiri {
130b86efd96Sagiri 	rds_alloc_cache = kmem_cache_create("rds_alloc_cache",
131b86efd96Sagiri 	    sizeof (rds_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
132b86efd96Sagiri 	rds_hash_init();
133b86efd96Sagiri 	/*
134b86efd96Sagiri 	 * kstats
135b86efd96Sagiri 	 */
136b86efd96Sagiri 	rds_kstatsp = kstat_create("rds", 0,
137bd670b35SErik Nordmark 	    "rds_kstat", "misc", KSTAT_TYPE_NAMED,
138bd670b35SErik Nordmark 	    sizeof (rds_kstat) / sizeof (kstat_named_t),
139bd670b35SErik Nordmark 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
140b86efd96Sagiri 	if (rds_kstatsp != NULL) {
141b86efd96Sagiri 		rds_kstatsp->ks_lock = &rds_kstat_mutex;
142b86efd96Sagiri 		rds_kstatsp->ks_data = (void *)&rds_kstat;
143b86efd96Sagiri 		kstat_install(rds_kstatsp);
144b86efd96Sagiri 	}
145b86efd96Sagiri }
146b86efd96Sagiri 
147b86efd96Sagiri #define	UINT_32_BITS 31
148b86efd96Sagiri void
rds_hash_init()149b86efd96Sagiri rds_hash_init()
150b86efd96Sagiri {
151b86efd96Sagiri 	int i;
152b86efd96Sagiri 
153*de710d24SJosef 'Jeff' Sipek 	if (!ISP2(rds_bind_fanout_size)) {
154b86efd96Sagiri 		/* Not a power of two. Round up to nearest power of two */
155b86efd96Sagiri 		for (i = 0; i < UINT_32_BITS; i++) {
156b86efd96Sagiri 			if (rds_bind_fanout_size < (1 << i))
157b86efd96Sagiri 				break;
158b86efd96Sagiri 		}
159b86efd96Sagiri 		rds_bind_fanout_size = 1 << i;
160b86efd96Sagiri 	}
161b86efd96Sagiri 	rds_bind_fanout = kmem_zalloc(rds_bind_fanout_size *
162b86efd96Sagiri 	    sizeof (rds_bf_t), KM_SLEEP);
163b86efd96Sagiri 	for (i = 0; i < rds_bind_fanout_size; i++) {
164b86efd96Sagiri 		mutex_init(&rds_bind_fanout[i].rds_bf_lock, NULL, MUTEX_DEFAULT,
165b86efd96Sagiri 		    NULL);
166b86efd96Sagiri 	}
167b86efd96Sagiri }
168b86efd96Sagiri 
169b86efd96Sagiri void
rds_free(rds_t * rds)170b86efd96Sagiri rds_free(rds_t *rds)
171b86efd96Sagiri {
172b86efd96Sagiri 	ASSERT(rds->rds_refcnt == 0);
173b86efd96Sagiri 	ASSERT(MUTEX_HELD(&rds->rds_lock));
174b86efd96Sagiri 	crfree(rds->rds_cred);
175b86efd96Sagiri 	kmem_cache_free(rds_alloc_cache, rds);
176b86efd96Sagiri }
177b86efd96Sagiri 
178b86efd96Sagiri rds_t *
rds_create(void * rds_ulpd,cred_t * credp)179b86efd96Sagiri rds_create(void *rds_ulpd, cred_t *credp)
180b86efd96Sagiri {
181b86efd96Sagiri 	rds_t	*rds;
182b86efd96Sagiri 
183b86efd96Sagiri 	/* User must supply a credential. */
184b86efd96Sagiri 	if (credp == NULL)
185b86efd96Sagiri 		return (NULL);
186b86efd96Sagiri 	rds = kmem_cache_alloc(rds_alloc_cache, KM_SLEEP);
187b86efd96Sagiri 	if (rds == NULL) {
188b86efd96Sagiri 		return (NULL);
189b86efd96Sagiri 	}
190b86efd96Sagiri 
191b86efd96Sagiri 	bzero(rds, sizeof (rds_t));
192b86efd96Sagiri 	mutex_init(&rds->rds_lock, NULL, MUTEX_DEFAULT, NULL);
193b86efd96Sagiri 	cv_init(&rds->rds_refcv, NULL, CV_DEFAULT, NULL);
194b86efd96Sagiri 	rds->rds_cred = credp;
195b86efd96Sagiri 	rds->rds_ulpd = rds_ulpd;
196b86efd96Sagiri 	rds->rds_zoneid = getzoneid();
197b86efd96Sagiri 	crhold(credp);
198b86efd96Sagiri 	rds->rds_refcnt++;
199b86efd96Sagiri 	return (rds);
200b86efd96Sagiri }
201b86efd96Sagiri 
202b86efd96Sagiri 
203b86efd96Sagiri /*
204b86efd96Sagiri  * Hash list removal routine for rds_t structures.
205b86efd96Sagiri  */
206b86efd96Sagiri void
rds_bind_hash_remove(rds_t * rds,boolean_t caller_holds_lock)207b86efd96Sagiri rds_bind_hash_remove(rds_t *rds, boolean_t caller_holds_lock)
208b86efd96Sagiri {
209b86efd96Sagiri 	rds_t   *rdsnext;
210b86efd96Sagiri 	kmutex_t *lockp;
211b86efd96Sagiri 
212b86efd96Sagiri 	if (rds->rds_ptpbhn == NULL)
213b86efd96Sagiri 		return;
214b86efd96Sagiri 
215b86efd96Sagiri 	/*
216b86efd96Sagiri 	 * Extract the lock pointer in case there are concurrent
217b86efd96Sagiri 	 * hash_remove's for this instance.
218b86efd96Sagiri 	 */
219b86efd96Sagiri 	ASSERT(rds->rds_port != 0);
220b86efd96Sagiri 	if (!caller_holds_lock) {
221b86efd96Sagiri 		lockp = &rds_bind_fanout[RDS_BIND_HASH(rds->rds_port)].
222b86efd96Sagiri 		    rds_bf_lock;
223b86efd96Sagiri 		ASSERT(lockp != NULL);
224b86efd96Sagiri 		mutex_enter(lockp);
225b86efd96Sagiri 	}
226b86efd96Sagiri 
227b86efd96Sagiri 	if (rds->rds_ptpbhn != NULL) {
228b86efd96Sagiri 		rdsnext = rds->rds_bind_hash;
229b86efd96Sagiri 		if (rdsnext != NULL) {
230b86efd96Sagiri 			rdsnext->rds_ptpbhn = rds->rds_ptpbhn;
231b86efd96Sagiri 			rds->rds_bind_hash = NULL;
232b86efd96Sagiri 		}
233b86efd96Sagiri 		*rds->rds_ptpbhn = rdsnext;
234b86efd96Sagiri 		rds->rds_ptpbhn = NULL;
235b86efd96Sagiri 	}
236b86efd96Sagiri 
237b86efd96Sagiri 	RDS_DEC_REF_CNT(rds);
238b86efd96Sagiri 
239b86efd96Sagiri 	if (!caller_holds_lock) {
240b86efd96Sagiri 		mutex_exit(lockp);
241b86efd96Sagiri 	}
242b86efd96Sagiri }
243b86efd96Sagiri 
244b86efd96Sagiri void
rds_bind_hash_insert(rds_bf_t * rdsbf,rds_t * rds)245b86efd96Sagiri rds_bind_hash_insert(rds_bf_t *rdsbf, rds_t *rds)
246b86efd96Sagiri {
247b86efd96Sagiri 	rds_t   **rdsp;
248b86efd96Sagiri 	rds_t   *rdsnext;
249b86efd96Sagiri 
250b86efd96Sagiri 	ASSERT(MUTEX_HELD(&rdsbf->rds_bf_lock));
251b86efd96Sagiri 	if (rds->rds_ptpbhn != NULL) {
252b86efd96Sagiri 		rds_bind_hash_remove(rds, B_TRUE);
253b86efd96Sagiri 	}
254b86efd96Sagiri 
255b86efd96Sagiri 	rdsp = &rdsbf->rds_bf_rds;
256b86efd96Sagiri 	rdsnext = rdsp[0];
257b86efd96Sagiri 
258b86efd96Sagiri 	if (rdsnext != NULL) {
259b86efd96Sagiri 		rdsnext->rds_ptpbhn = &rds->rds_bind_hash;
260b86efd96Sagiri 	}
261b86efd96Sagiri 	rds->rds_bind_hash = rdsnext;
262b86efd96Sagiri 	rds->rds_ptpbhn = rdsp;
263b86efd96Sagiri 	rdsp[0] = rds;
264b86efd96Sagiri 	RDS_INCR_REF_CNT(rds);
265b86efd96Sagiri 
266b86efd96Sagiri }
267b86efd96Sagiri 
268b86efd96Sagiri /*
269b86efd96Sagiri  * Everything is in network byte order
270b86efd96Sagiri  */
271b86efd96Sagiri /* ARGSUSED */
272b86efd96Sagiri 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)273b86efd96Sagiri rds_fanout(ipaddr_t local_addr, ipaddr_t rem_addr,
274b86efd96Sagiri     in_port_t local_port, in_port_t rem_port, zoneid_t zoneid)
275b86efd96Sagiri {
276b86efd96Sagiri 	rds_t	*rds;
277b86efd96Sagiri 	rds_bf_t *rdsbf;
278b86efd96Sagiri 
279b86efd96Sagiri 	rdsbf = &rds_bind_fanout[RDS_BIND_HASH(local_port)];
280b86efd96Sagiri 	mutex_enter(&rdsbf->rds_bf_lock);
281b86efd96Sagiri 	rds = rdsbf->rds_bf_rds;
282b86efd96Sagiri 	while (rds != NULL) {
283b86efd96Sagiri 		if (!(rds->rds_flags & RDS_CLOSING)) {
284b86efd96Sagiri 			if ((RDS_MATCH(rds, local_port, local_addr)) &&
285b86efd96Sagiri 			    ((local_addr != INADDR_LOOPBACK) ||
286b86efd96Sagiri 			    (rds->rds_zoneid == zoneid))) {
287b86efd96Sagiri 				RDS_INCR_REF_CNT(rds);
288b86efd96Sagiri 				break;
289b86efd96Sagiri 			}
290b86efd96Sagiri 		}
291b86efd96Sagiri 		rds = rds->rds_bind_hash;
292b86efd96Sagiri 	}
293b86efd96Sagiri 	mutex_exit(&rdsbf->rds_bf_lock);
294b86efd96Sagiri 	return (rds);
295b86efd96Sagiri }
296b86efd96Sagiri 
297b86efd96Sagiri boolean_t
rds_islocal(ipaddr_t addr)298b86efd96Sagiri rds_islocal(ipaddr_t addr)
299b86efd96Sagiri {
300f4b3ec61Sdh 	ip_stack_t *ipst;
301f4b3ec61Sdh 
302f4b3ec61Sdh 	ipst = netstack_find_by_zoneid(GLOBAL_ZONEID)->netstack_ip;
303f4b3ec61Sdh 	ASSERT(ipst != NULL);
304bd670b35SErik Nordmark 	if (ip_laddr_verify_v4(addr, ALL_ZONES, ipst, B_FALSE) == IPVL_BAD) {
305bd670b35SErik Nordmark 		netstack_rele(ipst->ips_netstack);
306b86efd96Sagiri 		return (B_FALSE);
307bd670b35SErik Nordmark 	}
308bd670b35SErik Nordmark 	netstack_rele(ipst->ips_netstack);
309b86efd96Sagiri 	return (B_TRUE);
310b86efd96Sagiri }
311