/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * rpcb_stat.c * Allows for gathering of statistics * * Copyright (c) 1990 by Sun Microsystems, Inc. */ /* * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ #include #include #include #include #include #ifdef PORTMAP #include #endif #include #include #include #include #include #include #include "rpcbind.h" static rpcb_stat_byvers inf; static rwlock_t inf_lock = DEFAULTRWLOCK; void rpcbs_procinfo(int rtype, rpcproc_t proc) { assert(rtype >= 0 && rtype < RPCBVERS_STAT); #ifdef PORTMAP if ((rtype == RPCBVERS_2_STAT) && (proc > rpcb_highproc_2)) return; #else assert(rtype != RPCBVERS_2_STAT); #endif if ((rtype == RPCBVERS_3_STAT) && (proc > rpcb_highproc_3)) return; if ((rtype == RPCBVERS_4_STAT) && (proc > rpcb_highproc_4)) return; atomic_add_int((uint_t *)&inf[rtype].info[proc], 1); } void rpcbs_set(int rtype, bool_t success) { assert(rtype >= 0 && rtype < RPCBVERS_STAT); if (success == FALSE) return; atomic_add_int((uint_t *)&inf[rtype].setinfo, 1); } void rpcbs_unset(int rtype, bool_t success) { assert(rtype >= 0 && rtype < RPCBVERS_STAT); if (success == FALSE) return; atomic_add_int((uint_t *)&inf[rtype].unsetinfo, 1); } void rpcbs_getaddr(int rtype, rpcprog_t prog, rpcvers_t vers, char *netid, char *uaddr) { rpcbs_addrlist *al; rpcbs_addrlist *s; rpcbs_addrlist *wal; struct netconfig *nconf; assert(rtype >= 0 && rtype < RPCBVERS_STAT); /* * First try with read lock only. */ (void) rw_rdlock(&inf_lock); for (s = al = inf[rtype].addrinfo; al; al = al->next) { if ((al->prog == prog) && (al->vers == vers) && (strcmp(al->netid, netid) == 0)) { (void) rw_unlock(&inf_lock); if ((uaddr == NULL) || (uaddr[0] == '\0')) atomic_add_int((uint_t *)&al->failure, 1); else atomic_add_int((uint_t *)&al->success, 1); return; } } (void) rw_unlock(&inf_lock); /* * If not found, we will likely need to add a new entry, * so pre-allocate it, and then try to search again with write lock. */ nconf = rpcbind_get_conf(netid); if (nconf == NULL) { return; } al = (rpcbs_addrlist *) malloc(sizeof (rpcbs_addrlist)); if (al == NULL) { return; } al->prog = prog; al->vers = vers; al->netid = nconf->nc_netid; if ((uaddr == NULL) || (uaddr[0] == '\0')) { al->failure = 1; al->success = 0; } else { al->failure = 0; al->success = 1; } (void) rw_wrlock(&inf_lock); for (wal = inf[rtype].addrinfo; wal != s; wal = wal->next) { if ((wal->prog == prog) && (wal->vers == vers) && (strcmp(wal->netid, netid) == 0)) { (void) rw_unlock(&inf_lock); free(al); if ((uaddr == NULL) || (uaddr[0] == '\0')) atomic_add_int((uint_t *)&wal->failure, 1); else atomic_add_int((uint_t *)&wal->success, 1); return; } } al->next = inf[rtype].addrinfo; inf[rtype].addrinfo = al; (void) rw_unlock(&inf_lock); } /* * rpcbproc - rpcbind proc number on which this was called */ void rpcbs_rmtcall(int rtype, rpcproc_t rpcbproc, rpcprog_t prog, rpcvers_t vers, rpcproc_t proc, char *netid, rpcblist_ptr rbl) { rpcbs_rmtcalllist *rl; rpcbs_rmtcalllist *s; rpcbs_rmtcalllist *wrl; struct netconfig *nconf; assert(rtype >= 0 && rtype < RPCBVERS_STAT); /* * First try with read lock only. */ (void) rw_rdlock(&inf_lock); for (s = rl = inf[rtype].rmtinfo; rl; rl = rl->next) { if ((rl->prog == prog) && (rl->vers == vers) && (rl->proc == proc) && (strcmp(rl->netid, netid) == 0)) { (void) rw_unlock(&inf_lock); if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers)) atomic_add_int((uint_t *)&rl->failure, 1); else atomic_add_int((uint_t *)&rl->success, 1); if (rpcbproc == RPCBPROC_INDIRECT) atomic_add_int((uint_t *)&rl->indirect, 1); return; } } (void) rw_unlock(&inf_lock); /* * If not found, we will likely need to add a new entry, * so pre-allocate it, and then try to search again with write lock. */ nconf = rpcbind_get_conf(netid); if (nconf == NULL) { return; } rl = (rpcbs_rmtcalllist *) malloc(sizeof (rpcbs_rmtcalllist)); if (rl == NULL) { return; } rl->prog = prog; rl->vers = vers; rl->proc = proc; rl->netid = nconf->nc_netid; if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers)) { rl->failure = 1; rl->success = 0; } else { rl->failure = 0; rl->success = 1; } rl->indirect = rpcbproc == RPCBPROC_INDIRECT ? 1 : 0; (void) rw_wrlock(&inf_lock); for (wrl = inf[rtype].rmtinfo; wrl != s; wrl = wrl->next) { if ((wrl->prog == prog) && (wrl->vers == vers) && (wrl->proc == proc) && (strcmp(wrl->netid, netid) == 0)) { (void) rw_unlock(&inf_lock); free(rl); if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers)) atomic_add_int((uint_t *)&wrl->failure, 1); else atomic_add_int((uint_t *)&wrl->success, 1); if (rpcbproc == RPCBPROC_INDIRECT) atomic_add_int((uint_t *)&wrl->indirect, 1); return; } } rl->next = inf[rtype].rmtinfo; inf[rtype].rmtinfo = rl; (void) rw_unlock(&inf_lock); } /* ARGSUSED */ bool_t rpcbproc_getstat(void *argp, rpcb_stat_byvers **result) { /* * inf_lock is unlocked in xdr_rpcb_stat_byvers_ptr() */ (void) rw_rdlock(&inf_lock); *result = &inf; return (TRUE); } bool_t xdr_rpcb_stat_byvers_ptr(XDR *xdrs, rpcb_stat_byvers **objp) { if (xdrs->x_op == XDR_FREE) { /* * inf_lock is locked in rpcbproc_getstat() */ (void) rw_unlock(&inf_lock); return (TRUE); } return (xdr_rpcb_stat_byvers(xdrs, (rpcb_stat *)*objp)); }