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