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
rpcbs_procinfo(int rtype,rpcproc_t proc)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
rpcbs_set(int rtype,bool_t success)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
rpcbs_unset(int rtype,bool_t success)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
rpcbs_getaddr(int rtype,rpcprog_t prog,rpcvers_t vers,char * netid,char * uaddr)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
rpcbs_rmtcall(int rtype,rpcproc_t rpcbproc,rpcprog_t prog,rpcvers_t vers,rpcproc_t proc,char * netid,rpcblist_ptr rbl)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
rpcbproc_getstat(void * argp,rpcb_stat_byvers ** result)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
xdr_rpcb_stat_byvers_ptr(XDR * xdrs,rpcb_stat_byvers ** objp)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