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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * rpcb_stat.c 24 * Allows for gathering of statistics 25 * 26 * Copyright (c) 1990 by Sun Microsystems, Inc. 27 */ 28 /* 29 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 30 */ 31 32 #include <stdio.h> 33 #include <netconfig.h> 34 #include <rpc/rpc.h> 35 #include <rpc/rpcb_prot.h> 36 #include <sys/stat.h> 37 #ifdef PORTMAP 38 #include <rpc/pmap_prot.h> 39 #endif 40 #include <stdlib.h> 41 #include <atomic.h> 42 #include <assert.h> 43 #include <thread.h> 44 #include <synch.h> 45 #include <string.h> 46 #include "rpcbind.h" 47 48 static rpcb_stat_byvers inf; 49 static rwlock_t inf_lock = DEFAULTRWLOCK; 50 51 void 52 rpcbs_procinfo(int rtype, rpcproc_t proc) 53 { 54 assert(rtype >= 0 && rtype < RPCBVERS_STAT); 55 56 #ifdef PORTMAP 57 if ((rtype == RPCBVERS_2_STAT) && (proc > rpcb_highproc_2)) 58 return; 59 #else 60 assert(rtype != RPCBVERS_2_STAT); 61 #endif 62 63 if ((rtype == RPCBVERS_3_STAT) && (proc > rpcb_highproc_3)) 64 return; 65 66 if ((rtype == RPCBVERS_4_STAT) && (proc > rpcb_highproc_4)) 67 return; 68 69 atomic_add_int((uint_t *)&inf[rtype].info[proc], 1); 70 } 71 72 void 73 rpcbs_set(int rtype, bool_t success) 74 { 75 assert(rtype >= 0 && rtype < RPCBVERS_STAT); 76 77 if (success == FALSE) 78 return; 79 80 atomic_add_int((uint_t *)&inf[rtype].setinfo, 1); 81 } 82 83 void 84 rpcbs_unset(int rtype, bool_t success) 85 { 86 assert(rtype >= 0 && rtype < RPCBVERS_STAT); 87 88 if (success == FALSE) 89 return; 90 91 atomic_add_int((uint_t *)&inf[rtype].unsetinfo, 1); 92 } 93 94 void 95 rpcbs_getaddr(int rtype, rpcprog_t prog, rpcvers_t vers, char *netid, 96 char *uaddr) 97 { 98 rpcbs_addrlist *al; 99 rpcbs_addrlist *s; 100 rpcbs_addrlist *wal; 101 struct netconfig *nconf; 102 103 assert(rtype >= 0 && rtype < RPCBVERS_STAT); 104 105 /* 106 * First try with read lock only. 107 */ 108 (void) rw_rdlock(&inf_lock); 109 for (s = al = inf[rtype].addrinfo; al; al = al->next) { 110 if ((al->prog == prog) && (al->vers == vers) && 111 (strcmp(al->netid, netid) == 0)) { 112 (void) rw_unlock(&inf_lock); 113 114 if ((uaddr == NULL) || (uaddr[0] == '\0')) 115 atomic_add_int((uint_t *)&al->failure, 1); 116 else 117 atomic_add_int((uint_t *)&al->success, 1); 118 119 return; 120 } 121 } 122 (void) rw_unlock(&inf_lock); 123 124 /* 125 * If not found, we will likely need to add a new entry, 126 * so pre-allocate it, and then try to search again with write lock. 127 */ 128 nconf = rpcbind_get_conf(netid); 129 if (nconf == NULL) { 130 return; 131 } 132 133 al = (rpcbs_addrlist *) malloc(sizeof (rpcbs_addrlist)); 134 if (al == NULL) { 135 return; 136 } 137 138 al->prog = prog; 139 al->vers = vers; 140 al->netid = nconf->nc_netid; 141 if ((uaddr == NULL) || (uaddr[0] == '\0')) { 142 al->failure = 1; 143 al->success = 0; 144 } else { 145 al->failure = 0; 146 al->success = 1; 147 } 148 149 (void) rw_wrlock(&inf_lock); 150 for (wal = inf[rtype].addrinfo; wal != s; wal = wal->next) { 151 if ((wal->prog == prog) && (wal->vers == vers) && 152 (strcmp(wal->netid, netid) == 0)) { 153 (void) rw_unlock(&inf_lock); 154 155 free(al); 156 157 if ((uaddr == NULL) || (uaddr[0] == '\0')) 158 atomic_add_int((uint_t *)&wal->failure, 1); 159 else 160 atomic_add_int((uint_t *)&wal->success, 1); 161 162 return; 163 } 164 } 165 166 al->next = inf[rtype].addrinfo; 167 inf[rtype].addrinfo = al; 168 (void) rw_unlock(&inf_lock); 169 } 170 171 /* 172 * rpcbproc - rpcbind proc number on which this was called 173 */ 174 void 175 rpcbs_rmtcall(int rtype, rpcproc_t rpcbproc, rpcprog_t prog, rpcvers_t vers, 176 rpcproc_t proc, char *netid, rpcblist_ptr rbl) 177 { 178 rpcbs_rmtcalllist *rl; 179 rpcbs_rmtcalllist *s; 180 rpcbs_rmtcalllist *wrl; 181 struct netconfig *nconf; 182 183 assert(rtype >= 0 && rtype < RPCBVERS_STAT); 184 185 /* 186 * First try with read lock only. 187 */ 188 (void) rw_rdlock(&inf_lock); 189 for (s = rl = inf[rtype].rmtinfo; rl; rl = rl->next) { 190 if ((rl->prog == prog) && (rl->vers == vers) && 191 (rl->proc == proc) && (strcmp(rl->netid, netid) == 0)) { 192 (void) rw_unlock(&inf_lock); 193 194 if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers)) 195 atomic_add_int((uint_t *)&rl->failure, 1); 196 else 197 atomic_add_int((uint_t *)&rl->success, 1); 198 if (rpcbproc == RPCBPROC_INDIRECT) 199 atomic_add_int((uint_t *)&rl->indirect, 1); 200 201 return; 202 } 203 } 204 (void) rw_unlock(&inf_lock); 205 206 /* 207 * If not found, we will likely need to add a new entry, 208 * so pre-allocate it, and then try to search again with write lock. 209 */ 210 nconf = rpcbind_get_conf(netid); 211 if (nconf == NULL) { 212 return; 213 } 214 215 rl = (rpcbs_rmtcalllist *) malloc(sizeof (rpcbs_rmtcalllist)); 216 if (rl == NULL) { 217 return; 218 } 219 220 rl->prog = prog; 221 rl->vers = vers; 222 rl->proc = proc; 223 rl->netid = nconf->nc_netid; 224 if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers)) { 225 rl->failure = 1; 226 rl->success = 0; 227 } else { 228 rl->failure = 0; 229 rl->success = 1; 230 } 231 rl->indirect = rpcbproc == RPCBPROC_INDIRECT ? 1 : 0; 232 233 (void) rw_wrlock(&inf_lock); 234 for (wrl = inf[rtype].rmtinfo; wrl != s; wrl = wrl->next) { 235 if ((wrl->prog == prog) && (wrl->vers == vers) && 236 (wrl->proc == proc) && (strcmp(wrl->netid, netid) == 0)) { 237 (void) rw_unlock(&inf_lock); 238 239 free(rl); 240 241 if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers)) 242 atomic_add_int((uint_t *)&wrl->failure, 1); 243 else 244 atomic_add_int((uint_t *)&wrl->success, 1); 245 if (rpcbproc == RPCBPROC_INDIRECT) 246 atomic_add_int((uint_t *)&wrl->indirect, 1); 247 248 return; 249 } 250 } 251 252 rl->next = inf[rtype].rmtinfo; 253 inf[rtype].rmtinfo = rl; 254 (void) rw_unlock(&inf_lock); 255 } 256 257 /* ARGSUSED */ 258 bool_t 259 rpcbproc_getstat(void *argp, rpcb_stat_byvers **result) 260 { 261 /* 262 * inf_lock is unlocked in xdr_rpcb_stat_byvers_ptr() 263 */ 264 (void) rw_rdlock(&inf_lock); 265 *result = &inf; 266 return (TRUE); 267 } 268 269 bool_t 270 xdr_rpcb_stat_byvers_ptr(XDR *xdrs, rpcb_stat_byvers **objp) 271 { 272 if (xdrs->x_op == XDR_FREE) { 273 /* 274 * inf_lock is locked in rpcbproc_getstat() 275 */ 276 (void) rw_unlock(&inf_lock); 277 return (TRUE); 278 } 279 280 return (xdr_rpcb_stat_byvers(xdrs, (rpcb_stat *)*objp)); 281 } 282