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