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