3321630ae991ab6dc9427865eccd3bb9b92eb3ca
1 /**
2 * collectd - src/nfs.c
3 * Copyright (C) 2005 Jason Pepas
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Authors:
20 * Jason Pepas <cell at ices.utexas.edu>
21 * Florian octo Forster <octo at verplant.org>
22 **/
24 #include "nfs.h"
26 #if COLLECT_NFS
27 #define MODULE_NAME "nfs"
29 #include "plugin.h"
30 #include "common.h"
32 static char *nfs2_procedures_file = "nfs2_procedures-%s.rrd";
33 static char *nfs3_procedures_file = "nfs3_procedures-%s.rrd";
35 /*
36 see /proc/net/rpc/nfs
37 see http://www.missioncriticallinux.com/orph/NFS-Statistics
39 net x x x x
40 rpc_stat.netcnt Not used; always zero.
41 rpc_stat.netudpcnt Not used; always zero.
42 rpc_stat.nettcpcnt Not used; always zero.
43 rpc_stat.nettcpconn Not used; always zero.
45 rpc x x x
46 rpc_stat.rpccnt The number of RPC calls.
47 rpc_stat.rpcretrans The number of retransmitted RPC calls.
48 rpc_stat.rpcauthrefresh The number of credential refreshes.
50 proc2 x x x...
51 proc3 x x x...
53 Procedure NFS Version NFS Version 3
54 Number Procedures Procedures
56 0 null null
57 1 getattr getattr
58 2 setattr setattr
59 3 root lookup
60 4 lookup access
61 5 readlink readlink
62 6 read read
63 7 wrcache write
64 8 write create
65 9 create mkdir
66 10 remove symlink
67 11 rename mknod
68 12 link remove
69 13 symlink rmdir
70 14 mkdir rename
71 15 rmdir link
72 16 readdir readdir
73 17 fsstat readdirplus
74 18 fsstat
75 19 fsinfo
76 20 pathconf
77 21 commit
78 */
80 static char *nfs2_procedures_ds_def[] =
81 {
82 "DS:null:COUNTER:25:0:U",
83 "DS:getattr:COUNTER:25:0:U",
84 "DS:setattr:COUNTER:25:0:U",
85 "DS:root:COUNTER:25:0:U",
86 "DS:lookup:COUNTER:25:0:U",
87 "DS:readlink:COUNTER:25:0:U",
88 "DS:read:COUNTER:25:0:U",
89 "DS:wrcache:COUNTER:25:0:U",
90 "DS:write:COUNTER:25:0:U",
91 "DS:create:COUNTER:25:0:U",
92 "DS:remove:COUNTER:25:0:U",
93 "DS:rename:COUNTER:25:0:U",
94 "DS:link:COUNTER:25:0:U",
95 "DS:symlink:COUNTER:25:0:U",
96 "DS:mkdir:COUNTER:25:0:U",
97 "DS:rmdir:COUNTER:25:0:U",
98 "DS:readdir:COUNTER:25:0:U",
99 "DS:fsstat:COUNTER:25:0:U",
100 NULL
101 };
102 static int nfs2_procedures_ds_num = 18;
104 static char *nfs3_procedures_ds_def[] =
105 {
106 "DS:null:COUNTER:25:0:U",
107 "DS:getattr:COUNTER:25:0:U",
108 "DS:setattr:COUNTER:25:0:U",
109 "DS:lookup:COUNTER:25:0:U",
110 "DS:access:COUNTER:25:0:U",
111 "DS:readlink:COUNTER:25:0:U",
112 "DS:read:COUNTER:25:0:U",
113 "DS:write:COUNTER:25:0:U",
114 "DS:create:COUNTER:25:0:U",
115 "DS:mkdir:COUNTER:25:0:U",
116 "DS:symlink:COUNTER:25:0:U",
117 "DS:mknod:COUNTER:25:0:U",
118 "DS:remove:COUNTER:25:0:U",
119 "DS:rmdir:COUNTER:25:0:U",
120 "DS:rename:COUNTER:25:0:U",
121 "DS:link:COUNTER:25:0:U",
122 "DS:readdir:COUNTER:25:0:U",
123 "DS:readdirplus:COUNTER:25:0:U",
124 "DS:fsstat:COUNTER:25:0:U",
125 "DS:fsinfo:COUNTER:25:0:U",
126 "DS:pathconf:COUNTER:25:0:U",
127 "DS:commit:COUNTER:25:0:U",
128 NULL
129 };
130 static int nfs3_procedures_ds_num = 22;
132 #ifdef HAVE_LIBKSTAT
133 extern kstat_ctl_t *kc;
134 static kstat_t *nfs2_ksp_client;
135 static kstat_t *nfs2_ksp_server;
136 static kstat_t *nfs3_ksp_client;
137 static kstat_t *nfs3_ksp_server;
138 static kstat_t *nfs4_ksp_client;
139 static kstat_t *nfs4_ksp_server;
140 #endif
142 /* Possibly TODO: NFSv4 statistics */
144 void nfs_init (void)
145 {
146 #ifdef HAVE_LIBKSTAT
147 kstat_t *ksp_chain;
149 nfs2_ksp_client = NULL;
150 nfs2_ksp_server = NULL;
151 nfs3_ksp_client = NULL;
152 nfs3_ksp_server = NULL;
153 nfs4_ksp_client = NULL;
154 nfs4_ksp_server = NULL;
156 if (kc == NULL)
157 return;
159 for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
160 ksp_chain = ksp_chain->ks_next)
161 {
162 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
163 continue;
164 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
165 nfs2_ksp_server = ksp_chain;
166 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
167 nfs3_ksp_server = ksp_chain;
168 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
169 nfs4_ksp_server = ksp_chain;
170 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
171 nfs2_ksp_client = ksp_chain;
172 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
173 nfs3_ksp_client = ksp_chain;
174 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
175 nfs4_ksp_client = ksp_chain;
176 }
177 #endif
179 return;
180 }
182 #define BUFSIZE 1024
183 void nfs2_procedures_write (char *host, char *inst, char *val)
184 {
185 char filename[BUFSIZE];
187 if (snprintf (filename, BUFSIZE, nfs2_procedures_file, inst) > BUFSIZE)
188 return;
190 rrd_update_file (host, filename, val, nfs2_procedures_ds_def,
191 nfs2_procedures_ds_num);
192 }
194 void nfs3_procedures_write (char *host, char *inst, char *val)
195 {
196 char filename[BUFSIZE];
198 if (snprintf (filename, BUFSIZE, nfs3_procedures_file, inst) > BUFSIZE)
199 return;
201 rrd_update_file (host, filename, val, nfs3_procedures_ds_def,
202 nfs3_procedures_ds_num);
203 }
205 void nfs2_procedures_submit (unsigned long long *val, char *inst)
206 {
207 char buf[BUFSIZE];
208 int retval = 0;
210 retval = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
211 "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
212 "%llu:%llu:%llu", /* 18x %llu */
213 (unsigned int) curtime,
214 val[0], val[1], val[2], val[3], val[4], val[5], val[6],
215 val[7], val[8], val[9], val[10], val[11], val[12],
216 val[13], val[14], val[15], val[16], val[17]);
219 if (retval >= BUFSIZE)
220 return;
221 else if (retval < 0)
222 {
223 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
224 return;
225 }
227 plugin_submit ("nfs2_procedures", inst, buf);
228 }
230 void nfs3_procedures_submit (unsigned long long *val, char *inst)
231 {
232 char buf[BUFSIZE];
233 int retval = 0;
235 retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
236 "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
237 "%llu:%llu:%llu:%llu:%llu:%llu:%llu", /* 22x %llu */
238 (unsigned int) curtime,
239 val[0], val[1], val[2], val[3], val[4], val[5], val[6],
240 val[7], val[8], val[9], val[10], val[11], val[12],
241 val[13], val[14], val[15], val[16], val[17], val[18],
242 val[19], val[20], val[21]);
244 if (retval >= BUFSIZE)
245 return;
246 else if (retval < 0)
247 {
248 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
249 return;
250 }
252 plugin_submit("nfs3_procedures", inst, buf);
253 }
255 #if defined(KERNEL_LINUX)
256 void nfs_read_stats_file (FILE *fh, char *inst)
257 {
258 char buffer[BUFSIZE];
260 char *fields[48];
261 int numfields = 0;
263 if (fh == NULL)
264 return;
266 while (fgets (buffer, BUFSIZE, fh) != NULL)
267 {
268 numfields = strsplit (buffer, fields, 48);
270 if (numfields < 2)
271 continue;
273 if (strncmp (fields[0], "proc2", 5) == 0)
274 {
275 int i;
276 unsigned long long *values;
278 if (numfields - 2 != nfs2_procedures_ds_num)
279 {
280 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS2 statistics.", numfields - 2);
281 continue;
282 }
284 if ((values = (unsigned long long *) malloc (nfs2_procedures_ds_num * sizeof (unsigned long long))) == NULL)
285 {
286 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
287 continue;
288 }
290 for (i = 0; i < nfs2_procedures_ds_num; i++)
291 values[i] = atoll (fields[i + 2]);
293 nfs2_procedures_submit (values, inst);
295 free (values);
296 }
297 else if (strncmp (fields[0], "proc3", 5) == 0)
298 {
299 int i;
300 unsigned long long *values;
302 if (numfields - 2 != nfs3_procedures_ds_num)
303 {
304 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS3 statistics.", numfields - 2);
305 continue;
306 }
308 if ((values = (unsigned long long *) malloc (nfs3_procedures_ds_num * sizeof (unsigned long long))) == NULL)
309 {
310 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
311 continue;
312 }
314 for (i = 0; i < nfs3_procedures_ds_num; i++)
315 values[i] = atoll (fields[i + 2]);
317 nfs3_procedures_submit (values, inst);
319 free (values);
320 }
321 }
322 }
323 #endif /* defined(KERNEL_LINUX) */
324 #undef BUFSIZE
326 #ifdef HAVE_LIBKSTAT
327 void nfs2_read_kstat (kstat_t *ksp, char *inst)
328 {
329 unsigned long long values[18];
331 values[0] = get_kstat_value (ksp, "null");
332 values[1] = get_kstat_value (ksp, "getattr");
333 values[2] = get_kstat_value (ksp, "setattr");
334 values[3] = get_kstat_value (ksp, "root");
335 values[4] = get_kstat_value (ksp, "lookup");
336 values[5] = get_kstat_value (ksp, "readlink");
337 values[6] = get_kstat_value (ksp, "read");
338 values[7] = get_kstat_value (ksp, "wrcache");
339 values[8] = get_kstat_value (ksp, "write");
340 values[9] = get_kstat_value (ksp, "create");
341 values[10] = get_kstat_value (ksp, "remove");
342 values[11] = get_kstat_value (ksp, "rename");
343 values[12] = get_kstat_value (ksp, "link");
344 values[13] = get_kstat_value (ksp, "symlink");
345 values[14] = get_kstat_value (ksp, "mkdir");
346 values[15] = get_kstat_value (ksp, "rmdir");
347 values[16] = get_kstat_value (ksp, "readdir");
348 values[17] = get_kstat_value (ksp, "statfs");
350 nfs2_procedures_submit (values, inst);
351 }
352 #endif
354 void nfs_read (void)
355 {
356 #if defined(KERNEL_LINUX)
357 FILE *fh;
359 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
360 {
361 nfs_read_stats_file (fh, "client");
362 fclose (fh);
363 }
365 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
366 {
367 nfs_read_stats_file (fh, "server");
368 fclose (fh);
369 }
371 /* #endif defined(KERNEL_LINUX) */
373 #elif defined(HAVE_LIBKSTAT)
374 if (nfs2_ksp_client != NULL)
375 nfs2_read_kstat (nfs2_ksp_client, "client");
376 if (nfs2_ksp_server != NULL)
377 nfs2_read_kstat (nfs2_ksp_server, "server");
378 #endif /* defined(HAVE_LIBKSTAT) */
379 }
381 void module_register (void)
382 {
383 plugin_register (MODULE_NAME, nfs_init, nfs_read, NULL);
384 plugin_register ("nfs2_procedures", NULL, NULL, nfs2_procedures_write);
385 plugin_register ("nfs3_procedures", NULL, NULL, nfs3_procedures_write);
386 }
388 #undef MODULE_NAME
389 #endif /* COLLECT_LOAD */