1/*	$OpenBSD: nfs.c,v 1.10 2024/05/18 09:02:34 jsg Exp $	*/
2
3/*
4 * Copyright (c) 2009 Jasper Lievisse Adriaanse <jasper@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20#include <sys/types.h>
21#include <sys/mount.h>
22#include <sys/signal.h>
23#include <sys/sysctl.h>
24#include <nfs/rpcv2.h>
25#include <nfs/nfsproto.h>
26#include <nfs/nfs.h>
27
28#include <err.h>
29#include <errno.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include "systat.h"
35
36int	select_client(void);
37int	select_server(void);
38int	read_nfs(void);
39void	print_client(void);
40void	print_server(void);
41
42struct	nfsstats nfsstats;
43int	num_client = 0;
44int	num_server = 0;
45
46field_def fields_nfs[] = {
47	/* Client */
48	{"RPC COUNTS", 10, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
49	{"", 12, 14, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
50	{"RPC INFO", 14, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
51	{"", 12, 14, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
52	{"CACHE INFO", 10, 12, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
53	{"", 12, 14, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
54
55	/* Server */
56	{"RPC COUNTS", 10, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
57	{"", 12, 14, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
58	{"CACHE STATS", 14, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
59	{"", 12, 14, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
60	{"WRITES", 10, 12, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
61	{"", 10, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
62};
63
64/* _V suffixed fields indicate a value column. */
65/* Client */
66#define	FLD_NFS_C_RPC_COUNTS	FIELD_ADDR(fields_nfs,0)
67#define	FLD_NFS_C_RPC_COUNTS_V	FIELD_ADDR(fields_nfs,1)
68#define	FLD_NFS_C_RPC_INFO	FIELD_ADDR(fields_nfs,2)
69#define	FLD_NFS_C_RPC_INFO_V	FIELD_ADDR(fields_nfs,3)
70#define	FLD_NFS_C_CACHE_INFO	FIELD_ADDR(fields_nfs,4)
71#define	FLD_NFS_C_CACHE_V	FIELD_ADDR(fields_nfs,5)
72
73/* Server */
74#define	FLD_NFS_S_RPC_COUNTS	FIELD_ADDR(fields_nfs,6)
75#define	FLD_NFS_S_RPC_COUNTS_V	FIELD_ADDR(fields_nfs,7)
76#define	FLD_NFS_S_CACHE_STATS	FIELD_ADDR(fields_nfs,8)
77#define	FLD_NFS_S_CACHE_STATS_V	FIELD_ADDR(fields_nfs,9)
78#define	FLD_NFS_S_WRITES	FIELD_ADDR(fields_nfs,10)
79#define	FLD_NFS_S_WRITES_V	FIELD_ADDR(fields_nfs,11)
80
81/* Define views */
82field_def *view_nfs_0[] = {
83	FLD_NFS_C_RPC_COUNTS, FLD_NFS_C_RPC_COUNTS_V, FLD_NFS_C_RPC_INFO,
84	FLD_NFS_C_RPC_INFO_V, FLD_NFS_C_CACHE_INFO, FLD_NFS_C_CACHE_V ,NULL
85};
86
87field_def *view_nfs_1[] = {
88	FLD_NFS_S_RPC_COUNTS, FLD_NFS_S_RPC_COUNTS_V, FLD_NFS_S_CACHE_STATS,
89	FLD_NFS_S_CACHE_STATS_V, FLD_NFS_S_WRITES, FLD_NFS_S_WRITES_V, NULL
90};
91
92/* Define view managers */
93struct view_manager nfs_client_mgr = {
94	"Client", select_client, read_nfs, NULL, print_header,
95	print_client, keyboard_callback, NULL, NULL
96};
97
98struct view_manager nfs_server_mgr = {
99	"Server", select_server, read_nfs, NULL, print_header,
100	print_server, keyboard_callback, NULL, NULL
101};
102
103field_view views_nfs[] = {
104	{view_nfs_0, "nfsclient", '8', &nfs_client_mgr},
105	{view_nfs_1, "nfsserver", '9', &nfs_server_mgr},
106	{NULL, NULL, 0, NULL}
107};
108
109int
110select_client(void)
111{
112	num_disp = num_client;
113	return(0);
114}
115
116int
117select_server(void)
118{
119	num_disp = num_server;
120	return(0);
121}
122
123int
124initnfs(void)
125{
126	field_view *v;
127
128	for (v = views_nfs; v->name != NULL; v++)
129		add_view(v);
130
131	read_nfs();
132
133	return(0);
134}
135
136/*
137 * We get all the information in one go and don't care about
138 * server or client fields (those will be '0' if not applicable).
139 */
140int
141read_nfs(void)
142{
143	struct nfsstats *p = &nfsstats;
144	int mib[3];
145	size_t len = sizeof(*p);
146
147	mib[0] = CTL_VFS;
148	mib[1] = 2; /* NETDEV */
149	mib[2] = NFS_NFSSTATS;
150
151	if (sysctl(mib, 3, p, &len, NULL, 0) == -1)
152		return(-1);
153	else
154		return(0);
155}
156
157
158/*
159 * As we want a view with multiple columns, mixed with labels and values,
160 * we can't use the regular dance and have to use our own (looong) dance
161 * to build the layout.
162 */
163void
164print_client(void)
165{
166	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Getattr");
167	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
168	  nfsstats.rpccnt[NFSPROC_GETATTR]);
169	print_fld_str(FLD_NFS_C_RPC_INFO, "TimedOut");
170	print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.rpctimeouts);
171	print_fld_str(FLD_NFS_C_CACHE_INFO, "Attr Hits  ");
172	print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.attrcache_hits);
173	end_line();
174
175	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Setattr");
176	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
177	  nfsstats.rpccnt[NFSPROC_SETATTR]);
178	print_fld_str(FLD_NFS_C_RPC_INFO, "Invalid");
179	print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.rpcinvalid);
180	print_fld_str(FLD_NFS_C_CACHE_INFO, "Attr Misses");
181	print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.attrcache_misses);
182	end_line();
183
184	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Lookup");
185	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
186	  nfsstats.rpccnt[NFSPROC_LOOKUP]);
187	print_fld_str(FLD_NFS_C_RPC_INFO, "X Replies");
188	print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.rpcunexpected);
189	print_fld_str(FLD_NFS_C_CACHE_INFO, "Lkup Hits  ");
190	print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.lookupcache_hits);
191	end_line();
192
193	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Readlink");
194	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
195	  nfsstats.rpccnt[NFSPROC_READLINK]);
196	print_fld_str(FLD_NFS_C_RPC_INFO, "Retries");
197	print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.rpcretries);
198	print_fld_str(FLD_NFS_C_CACHE_INFO, "Lkup Misses  ");
199	print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.lookupcache_misses);
200	end_line();
201
202	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Read");
203	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
204	  nfsstats.rpccnt[NFSPROC_READ]);
205	print_fld_str(FLD_NFS_C_RPC_INFO, "Requests");
206	print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.rpcrequests);
207	print_fld_str(FLD_NFS_C_CACHE_INFO, "BioR Hits  ");
208	print_fld_ssize(FLD_NFS_C_CACHE_V,
209	  nfsstats.biocache_reads-nfsstats.read_bios);
210	end_line();
211
212	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Write");
213	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V, nfsstats.rpccnt[NFSPROC_WRITE]);
214	print_fld_str(FLD_NFS_C_RPC_INFO, "FrcSync");
215	print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.forcedsync);
216	print_fld_str(FLD_NFS_C_CACHE_INFO, "BioR Misses");
217	print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.read_bios);
218	end_line();
219
220	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Create");
221	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
222	  nfsstats.rpccnt[NFSPROC_CREATE]);
223	print_fld_str(FLD_NFS_C_CACHE_INFO, "BioW Hits  ");
224	print_fld_ssize(FLD_NFS_C_CACHE_V,
225	  nfsstats.biocache_writes-nfsstats.write_bios);
226	end_line();
227
228	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Remove");
229	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
230	  nfsstats.rpccnt[NFSPROC_REMOVE]);
231	print_fld_str(FLD_NFS_C_CACHE_INFO, "BioW Misses");
232	print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.write_bios);
233	end_line();
234
235	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Rename");
236	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
237	  nfsstats.rpccnt[NFSPROC_RENAME]);
238	print_fld_str(FLD_NFS_C_CACHE_INFO, "BioRL Hits  ");
239	print_fld_ssize(FLD_NFS_C_CACHE_V,
240	  nfsstats.biocache_readlinks-nfsstats.readlink_bios);
241	end_line();
242
243	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Link");
244	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V, nfsstats.rpccnt[NFSPROC_LINK]);
245	print_fld_str(FLD_NFS_C_CACHE_INFO, "BioRL Misses");
246	print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.readlink_bios);
247	end_line();
248
249	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Symlink");
250	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
251	  nfsstats.rpccnt[NFSPROC_SYMLINK]);
252	print_fld_str(FLD_NFS_C_CACHE_INFO, "BioD Hits  ");
253	print_fld_ssize(FLD_NFS_C_CACHE_V,
254	  nfsstats.biocache_readdirs-nfsstats.readdir_bios);
255	end_line();
256
257	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Mkdir");
258	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V, nfsstats.rpccnt[NFSPROC_MKDIR]);
259	print_fld_str(FLD_NFS_C_CACHE_INFO, "BioD Misses");
260	print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.readdir_bios);
261	end_line();
262
263	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Rmdir");
264	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V, nfsstats.rpccnt[NFSPROC_RMDIR]);
265	print_fld_str(FLD_NFS_C_CACHE_INFO, "DirE Hits  ");
266	print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.direofcache_hits);
267	end_line();
268
269	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Readdir");
270	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
271	  nfsstats.rpccnt[NFSPROC_READDIR]);
272	print_fld_str(FLD_NFS_C_CACHE_INFO, "DirE Misses");
273	print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.direofcache_misses);
274	end_line();
275
276	print_fld_str(FLD_NFS_C_RPC_COUNTS, "RdirPlus");
277	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
278	  nfsstats.rpccnt[NFSPROC_READDIRPLUS]);
279	end_line();
280
281	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Access");
282	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
283	  nfsstats.rpccnt[NFSPROC_ACCESS]);
284	end_line();
285
286	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Mknod");
287	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V, nfsstats.rpccnt[NFSPROC_MKNOD]);
288	end_line();
289
290	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Fsstat");
291	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
292	  nfsstats.rpccnt[NFSPROC_FSSTAT]);
293	end_line();
294
295	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Fsinfo");
296	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
297	  nfsstats.rpccnt[NFSPROC_FSINFO]);
298	end_line();
299
300	print_fld_str(FLD_NFS_C_RPC_COUNTS, "PathConf");
301	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
302	  nfsstats.rpccnt[NFSPROC_PATHCONF]);
303	end_line();
304
305	print_fld_str(FLD_NFS_C_RPC_COUNTS, "Commit");
306	print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
307	  nfsstats.rpccnt[NFSPROC_COMMIT]);
308	end_line();
309}
310
311void
312print_server(void)
313{
314	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Getattr");
315	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
316	  nfsstats.srvrpccnt[NFSPROC_GETATTR]);
317	print_fld_str(FLD_NFS_S_CACHE_STATS, "Inprog");
318	print_fld_ssize(FLD_NFS_S_CACHE_STATS_V, nfsstats.srvcache_inproghits);
319	print_fld_str(FLD_NFS_S_WRITES, "WriteOps");
320	print_fld_ssize(FLD_NFS_S_WRITES_V, nfsstats.srvvop_writes);
321	end_line();
322
323	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Setattr");
324	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
325	  nfsstats.srvrpccnt[NFSPROC_SETATTR]);
326	print_fld_str(FLD_NFS_S_CACHE_STATS, "Idem");
327	print_fld_ssize(FLD_NFS_S_CACHE_STATS_V,
328	  nfsstats.srvcache_idemdonehits);
329	print_fld_str(FLD_NFS_S_WRITES, "WriteRPC");
330	print_fld_ssize(FLD_NFS_S_WRITES_V, nfsstats.srvrpccnt[NFSPROC_WRITE]);
331	end_line();
332
333	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Lookup");
334	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
335	  nfsstats.srvrpccnt[NFSPROC_LOOKUP]);
336	print_fld_str(FLD_NFS_S_CACHE_STATS, "Non-idem");
337	print_fld_ssize(FLD_NFS_S_CACHE_STATS_V,
338	  nfsstats.srvcache_nonidemdonehits);
339	print_fld_str(FLD_NFS_S_WRITES, "Opsaved");
340	print_fld_ssize(FLD_NFS_S_WRITES_V,
341	  nfsstats.srvrpccnt[NFSPROC_WRITE] - nfsstats.srvvop_writes);
342	end_line();
343
344	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Readlink");
345	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
346	  nfsstats.srvrpccnt[NFSPROC_READLINK]);
347	print_fld_str(FLD_NFS_S_CACHE_STATS, "Misses");
348	print_fld_ssize(FLD_NFS_S_CACHE_STATS_V, nfsstats.srvcache_misses);
349	end_line();
350
351	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Read");
352	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
353	  nfsstats.srvrpccnt[NFSPROC_READ]);
354	end_line();
355
356	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Write");
357	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
358	  nfsstats.srvrpccnt[NFSPROC_WRITE]);
359	end_line();
360
361	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Create");
362	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
363	  nfsstats.srvrpccnt[NFSPROC_CREATE]);
364	end_line();
365
366	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Remove");
367	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
368	  nfsstats.srvrpccnt[NFSPROC_REMOVE]);
369	end_line();
370
371	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Rename");
372	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
373	  nfsstats.srvrpccnt[NFSPROC_RENAME]);
374	end_line();
375
376	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Link");
377	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
378	  nfsstats.srvrpccnt[NFSPROC_LINK]);
379	end_line();
380
381	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Symlink");
382	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
383	  nfsstats.srvrpccnt[NFSPROC_SYMLINK]);
384	end_line();
385
386	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Mkdir");
387	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
388	  nfsstats.srvrpccnt[NFSPROC_MKDIR]);
389	end_line();
390
391	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Rmdir");
392	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
393	  nfsstats.srvrpccnt[NFSPROC_RMDIR]);
394	end_line();
395
396	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Readdir");
397	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
398	  nfsstats.srvrpccnt[NFSPROC_READDIR]);
399	end_line();
400
401	print_fld_str(FLD_NFS_S_RPC_COUNTS, "RdirPlus");
402	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
403	  nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]);
404	end_line();
405
406	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Access");
407	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
408	  nfsstats.srvrpccnt[NFSPROC_ACCESS]);
409	end_line();
410
411	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Mknod");
412	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
413	  nfsstats.srvrpccnt[NFSPROC_MKNOD]);
414	end_line();
415
416	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Fsstat");
417	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
418	  nfsstats.srvrpccnt[NFSPROC_FSSTAT]);
419	end_line();
420
421	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Fsinfo");
422	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
423	  nfsstats.srvrpccnt[NFSPROC_FSINFO]);
424	end_line();
425
426	print_fld_str(FLD_NFS_S_RPC_COUNTS, "PathConf");
427	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
428	  nfsstats.srvrpccnt[NFSPROC_PATHCONF]);
429	end_line();
430
431	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Commit");
432	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
433	  nfsstats.srvrpccnt[NFSPROC_COMMIT]);
434	end_line();
435
436	/* This creates an empty space on screen to separate the two blocks */
437	print_fld_str(FLD_NFS_S_RPC_COUNTS, "");
438	end_line();
439
440	print_fld_str(FLD_NFS_S_RPC_COUNTS, "Ret-Failed");
441	print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V, nfsstats.srvrpc_errs);
442	print_fld_str(FLD_NFS_S_CACHE_STATS, "Faults");
443	print_fld_ssize(FLD_NFS_S_CACHE_STATS_V, nfsstats.srv_errs);
444	end_line();
445}
446