1 /**
2 * collectd - src/nfs.c
3 * Copyright (C) 2005,2006 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; only version 2 of the License is applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Authors:
19 * Jason Pepas <cell at ices.utexas.edu>
20 * Florian octo Forster <octo at verplant.org>
21 **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
27 #if HAVE_KSTAT_H
28 #include <kstat.h>
29 #endif
31 /*
32 see /proc/net/rpc/nfs
33 see http://www.missioncriticallinux.com/orph/NFS-Statistics
35 net x x x x
36 rpc_stat.netcnt Not used; always zero.
37 rpc_stat.netudpcnt Not used; always zero.
38 rpc_stat.nettcpcnt Not used; always zero.
39 rpc_stat.nettcpconn Not used; always zero.
41 rpc x x x
42 rpc_stat.rpccnt The number of RPC calls.
43 rpc_stat.rpcretrans The number of retransmitted RPC calls.
44 rpc_stat.rpcauthrefresh The number of credential refreshes.
46 proc2 x x x...
47 proc3 x x x...
49 Procedure NFS Version NFS Version 3
50 Number Procedures Procedures
52 0 null null
53 1 getattr getattr
54 2 setattr setattr
55 3 root lookup
56 4 lookup access
57 5 readlink readlink
58 6 read read
59 7 wrcache write
60 8 write create
61 9 create mkdir
62 10 remove symlink
63 11 rename mknod
64 12 link remove
65 13 symlink rmdir
66 14 mkdir rename
67 15 rmdir link
68 16 readdir readdir
69 17 fsstat readdirplus
70 18 fsstat
71 19 fsinfo
72 20 pathconf
73 21 commit
74 */
76 static const char *nfs2_procedures_names[] =
77 {
78 "null",
79 "getattr",
80 "setattr",
81 "root",
82 "lookup",
83 "readlink",
84 "read",
85 "wrcache",
86 "write",
87 "create",
88 "remove",
89 "rename",
90 "link",
91 "symlink",
92 "mkdir",
93 "rmdir",
94 "readdir",
95 "fsstat",
96 NULL
97 };
98 static int nfs2_procedures_names_num = 18;
100 static const char *nfs3_procedures_names[] =
101 {
102 "null",
103 "getattr",
104 "setattr",
105 "lookup",
106 "access",
107 "readlink",
108 "read",
109 "write",
110 "create",
111 "mkdir",
112 "symlink",
113 "mknod",
114 "remove",
115 "rmdir",
116 "rename",
117 "link",
118 "readdir",
119 "readdirplus",
120 "fsstat",
121 "fsinfo",
122 "pathconf",
123 "commit",
124 NULL
125 };
126 static int nfs3_procedures_names_num = 22;
128 static const char *nfs4_procedures_names[] =
129 {
130 "null",
131 "compound",
132 "reserved",
133 "access",
134 "close",
135 "commit",
136 "create",
137 "delegpurge",
138 "delegreturn",
139 "getattr",
140 "getfh",
141 "link",
142 "lock",
143 "lockt",
144 "locku",
145 "lookup",
146 "lookupp",
147 "nverify",
148 "open",
149 "openattr",
150 "open_confirm",
151 "open_downgrade",
152 "putfh",
153 "putpubfh",
154 "putrootfh",
155 "read",
156 "readdir",
157 "readlink",
158 "remove",
159 "rename",
160 "renew",
161 "restorefh",
162 "savefh",
163 "secinfo",
164 "setattr",
165 "setclientid",
166 "setclientid_confirm",
167 "verify",
168 "write",
169 NULL
170 };
171 static int nfs4_procedures_names_num = 39;
173 #if HAVE_LIBKSTAT
174 extern kstat_ctl_t *kc;
175 static kstat_t *nfs2_ksp_client;
176 static kstat_t *nfs2_ksp_server;
177 static kstat_t *nfs3_ksp_client;
178 static kstat_t *nfs3_ksp_server;
179 static kstat_t *nfs4_ksp_client;
180 static kstat_t *nfs4_ksp_server;
181 #endif
183 /* Possibly TODO: NFSv4 statistics */
185 #if HAVE_LIBKSTAT
186 static int nfs_init (void)
187 {
188 kstat_t *ksp_chain = NULL;
190 nfs2_ksp_client = NULL;
191 nfs2_ksp_server = NULL;
192 nfs3_ksp_client = NULL;
193 nfs3_ksp_server = NULL;
194 nfs4_ksp_client = NULL;
195 nfs4_ksp_server = NULL;
197 if (kc == NULL)
198 return (-1);
200 for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
201 ksp_chain = ksp_chain->ks_next)
202 {
203 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
204 continue;
205 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
206 nfs2_ksp_server = ksp_chain;
207 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
208 nfs3_ksp_server = ksp_chain;
209 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
210 nfs4_ksp_server = ksp_chain;
211 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
212 nfs2_ksp_client = ksp_chain;
213 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
214 nfs3_ksp_client = ksp_chain;
215 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
216 nfs4_ksp_client = ksp_chain;
217 }
219 return (0);
220 } /* int nfs_init */
221 #endif
223 #define BUFSIZE 1024
224 #if HAVE_LIBKSTAT
226 static void nfs2_procedures_submit(unsigned long long *val,
227 const char *plugin_instance, char *nfs_ver, int len)
228 {
229 value_t values[1];
230 value_list_t vl = VALUE_LIST_INIT;
231 char pl_instance[30];
232 int i;
234 vl.values = values;
235 vl.values_len = 1;
236 sstrncpy(vl.host, hostname_g, sizeof (vl.host));
237 sstrncpy(vl.plugin, "nfs", sizeof (vl.plugin));
238 sstrncpy(pl_instance, nfs_ver, strlen(nfs_ver) + 1);
239 strcat(pl_instance, plugin_instance);
240 sstrncpy(vl.plugin_instance, pl_instance,
241 sizeof (vl.plugin_instance));
242 sstrncpy(vl.type, "nfs_procedure", sizeof (vl.type));
245 for (i = 0; i < len; i++)
246 {
247 values[0].derive = val[i];
248 if (strcmp(nfs_ver, "nfs2") == 0)
249 sstrncpy(vl.type_instance, nfs2_procedures_names[i],
250 sizeof (vl.type_instance));
251 else if (strcmp(nfs_ver, "nfs3") == 0)
252 sstrncpy(vl.type_instance, nfs3_procedures_names[i],
253 sizeof (vl.type_instance));
254 else if (strcmp(nfs_ver, "nfs4") == 0) {
255 sstrncpy(vl.type_instance, nfs4_procedures_names[i],
256 sizeof (vl.type_instance));
257 }
259 DEBUG("%s-%s/nfs_procedure-%s = %lld",
260 vl.plugin, vl.plugin_instance,
261 vl.type_instance, val[i]);
262 plugin_dispatch_values (&vl);
263 }
264 }
265 #endif
267 static void nfs_procedures_submit (const char *plugin_instance,
268 unsigned long long *val, const char **names, int len)
269 {
271 value_t values[1];
272 value_list_t vl = VALUE_LIST_INIT;
273 int i;
275 vl.values = values;
276 vl.values_len = 1;
277 sstrncpy(vl.host, hostname_g, sizeof (vl.host));
278 sstrncpy(vl.plugin, "nfs", sizeof (vl.plugin));
279 sstrncpy(vl.plugin_instance, plugin_instance,
280 sizeof (vl.plugin_instance));
281 sstrncpy(vl.type, "nfs_procedure", sizeof (vl.type));
283 for (i = 0; (val[i] != NULL) && (i < len); i++) {
284 values[0].derive = val[i];
285 sstrncpy(vl.type_instance, names[i],
286 sizeof (vl.type_instance));
287 DEBUG("%s-%s/nfs_procedure-%s = %llu",
288 vl.plugin, vl.plugin_instance,
289 vl.type_instance, val[i]);
290 plugin_dispatch_values(&vl);
291 }
292 } /* void nfs_procedures_submit */
294 static void nfs_read_stats_file (FILE *fh, char *inst)
295 {
296 char buffer[BUFSIZE];
298 char plugin_instance[DATA_MAX_NAME_LEN];
300 char *fields[48];
301 int numfields = 0;
303 if (fh == NULL)
304 return;
306 while (fgets (buffer, BUFSIZE, fh) != NULL)
307 {
308 numfields = strsplit (buffer, fields, 48);
310 if (((numfields - 2) != nfs2_procedures_names_num)
311 && ((numfields - 2)
312 != nfs3_procedures_names_num))
313 continue;
315 if (strcmp (fields[0], "proc2") == 0)
316 {
317 int i;
318 unsigned long long *values;
320 if ((numfields - 2) != nfs2_procedures_names_num)
321 {
322 WARNING ("nfs plugin: Wrong "
323 "number of fields (= %i) "
324 "for NFSv2 statistics.",
325 numfields - 2);
326 continue;
327 }
329 ssnprintf (plugin_instance, sizeof (plugin_instance),
330 "v2%s", inst);
332 values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
333 if (values == NULL)
334 {
335 char errbuf[1024];
336 ERROR ("nfs plugin: malloc "
337 "failed: %s",
338 sstrerror (errno, errbuf, sizeof (errbuf)));
339 continue;
340 }
342 for (i = 0; i < nfs2_procedures_names_num; i++)
343 values[i] = atoll (fields[i + 2]);
345 nfs_procedures_submit (plugin_instance, values,
346 nfs2_procedures_names,
347 nfs2_procedures_names_num);
349 free (values);
350 }
351 else if (strncmp (fields[0], "proc3", 5) == 0)
352 {
353 int i;
354 unsigned long long *values;
356 if ((numfields - 2) != nfs3_procedures_names_num)
357 {
358 WARNING ("nfs plugin: Wrong "
359 "number of fields (= %i) "
360 "for NFSv3 statistics.",
361 numfields - 2);
362 continue;
363 }
365 ssnprintf (plugin_instance, sizeof (plugin_instance),
366 "v3%s", inst);
368 values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
369 if (values == NULL)
370 {
371 char errbuf[1024];
372 ERROR ("nfs plugin: malloc "
373 "failed: %s",
374 sstrerror (errno, errbuf, sizeof (errbuf)));
375 continue;
376 }
378 for (i = 0; i < nfs3_procedures_names_num; i++)
379 values[i] = atoll (fields[i + 2]);
381 nfs_procedures_submit (plugin_instance, values,
382 nfs3_procedures_names,
383 nfs3_procedures_names_num);
385 free (values);
386 }
387 } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
388 } /* void nfs_read_stats_file */
389 #undef BUFSIZE
391 #if HAVE_LIBKSTAT
392 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
393 {
394 unsigned long long values[nfs2_procedures_names_num];
396 kstat_read(kc, ksp, NULL);
397 values[0] = get_kstat_value (ksp, "null");
398 values[1] = get_kstat_value (ksp, "getattr");
399 values[2] = get_kstat_value (ksp, "setattr");
400 values[3] = get_kstat_value (ksp, "root");
401 values[4] = get_kstat_value (ksp, "lookup");
402 values[5] = get_kstat_value (ksp, "readlink");
403 values[6] = get_kstat_value (ksp, "read");
404 values[7] = get_kstat_value (ksp, "wrcache");
405 values[8] = get_kstat_value (ksp, "write");
406 values[9] = get_kstat_value (ksp, "create");
407 values[10] = get_kstat_value (ksp, "remove");
408 values[11] = get_kstat_value (ksp, "rename");
409 values[12] = get_kstat_value (ksp, "link");
410 values[13] = get_kstat_value (ksp, "symlink");
411 values[14] = get_kstat_value (ksp, "mkdir");
412 values[15] = get_kstat_value (ksp, "rmdir");
413 values[16] = get_kstat_value (ksp, "readdir");
414 values[17] = get_kstat_value (ksp, "statfs");
416 nfs2_procedures_submit (values, inst, "nfs2", nfs2_procedures_names_num);
417 }
419 static void nfs3_read_kstat(kstat_t *ksp, char *inst)
420 {
421 unsigned long long values[nfs3_procedures_names_num];
423 kstat_read(kc, ksp, NULL);
424 values[0] = get_kstat_value (ksp, "null");
425 values[1] = get_kstat_value (ksp, "getattr");
426 values[2] = get_kstat_value (ksp, "setattr");
427 values[3] = get_kstat_value (ksp, "lookup");
428 values[4] = get_kstat_value (ksp, "access");
429 values[5] = get_kstat_value (ksp, "readlink");
430 values[6] = get_kstat_value (ksp, "read");
431 values[7] = get_kstat_value (ksp, "write");
432 values[8] = get_kstat_value (ksp, "create");
433 values[9] = get_kstat_value (ksp, "mkdir");
434 values[10] = get_kstat_value (ksp, "symlink");
435 values[11] = get_kstat_value (ksp, "mknod");
436 values[12] = get_kstat_value (ksp, "remove");
437 values[13] = get_kstat_value (ksp, "rmdir");
438 values[14] = get_kstat_value (ksp, "rename");
439 values[15] = get_kstat_value (ksp, "link");
440 values[16] = get_kstat_value (ksp, "readdir");
441 values[17] = get_kstat_value (ksp, "readdirplus");
442 values[18] = get_kstat_value (ksp, "fsstat");
443 values[19] = get_kstat_value (ksp, "fsinfo");
444 values[20] = get_kstat_value (ksp, "pathconf");
445 values[21] = get_kstat_value (ksp, "commit");
447 nfs2_procedures_submit (values, inst, "nfs3", nfs3_procedures_names_num);
448 }
450 static void nfs4_read_kstat(kstat_t *ksp, char *inst)
451 {
452 unsigned long long values[nfs4_procedures_names_num];
454 kstat_read(kc, ksp, NULL);
456 values[0] = get_kstat_value (ksp, "null");
457 values[1] = get_kstat_value (ksp, "compound");
458 values[2] = get_kstat_value (ksp, "reserved");
459 values[3] = get_kstat_value (ksp, "access");
460 values[4] = get_kstat_value (ksp, "close");
461 values[5] = get_kstat_value (ksp, "commit");
462 values[6] = get_kstat_value (ksp, "create");
463 values[7] = get_kstat_value (ksp, "delegpurge");
464 values[8] = get_kstat_value (ksp, "delegreturn");
465 values[9] = get_kstat_value (ksp, "getattr");
466 values[10] = get_kstat_value (ksp, "getfh");
467 values[11] = get_kstat_value (ksp, "link");
468 values[12] = get_kstat_value (ksp, "lock");
469 values[13] = get_kstat_value (ksp, "lockt");
470 values[14] = get_kstat_value (ksp, "locku");
471 values[15] = get_kstat_value (ksp, "lookup");
472 values[16] = get_kstat_value (ksp, "lookupp");
473 values[17] = get_kstat_value (ksp, "nverify");
474 values[18] = get_kstat_value (ksp, "open");
475 values[19] = get_kstat_value (ksp, "openattr");
476 values[20] = get_kstat_value (ksp, "open_confirm");
477 values[21] = get_kstat_value (ksp, "open_downgrade");
478 values[22] = get_kstat_value (ksp, "putfh");
479 values[23] = get_kstat_value (ksp, "putpubfh");
480 values[24] = get_kstat_value (ksp, "putrootfh");
481 values[25] = get_kstat_value (ksp, "read");
482 values[26] = get_kstat_value (ksp, "readdir");
483 values[27] = get_kstat_value (ksp, "readlink");
484 values[28] = get_kstat_value (ksp, "remove");
485 values[29] = get_kstat_value (ksp, "rename");
486 values[30] = get_kstat_value (ksp, "renew");
487 values[31] = get_kstat_value (ksp, "restorefh");
488 values[32] = get_kstat_value (ksp, "savefh");
489 values[33] = get_kstat_value (ksp, "secinfo");
490 values[34] = get_kstat_value (ksp, "setattr");
491 values[35] = get_kstat_value (ksp, "setclientid");
492 values[36] = get_kstat_value (ksp, "setclientid_confirm");
493 values[37] = get_kstat_value (ksp, "verify");
494 values[38] = get_kstat_value (ksp, "write");
496 nfs2_procedures_submit (values, inst, "nfs4", nfs4_procedures_names_num);
497 }
498 #endif
500 static int nfs_read (void)
501 {
502 FILE *fh;
504 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
505 {
506 nfs_read_stats_file (fh, "client");
507 fclose (fh);
508 }
510 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
511 {
512 nfs_read_stats_file (fh, "server");
513 fclose (fh);
514 }
516 #if HAVE_LIBKSTAT
517 nfs_init ();
518 if (nfs2_ksp_client != NULL)
519 nfs2_read_kstat (nfs2_ksp_client, "client");
520 if (nfs2_ksp_server != NULL)
521 nfs2_read_kstat (nfs2_ksp_server, "server");
522 if (nfs3_ksp_client != NULL)
523 nfs3_read_kstat (nfs3_ksp_client, "client");
524 if (nfs3_ksp_server != NULL)
525 nfs3_read_kstat (nfs3_ksp_server, "server");
526 if (nfs4_ksp_client != NULL)
527 nfs4_read_kstat (nfs4_ksp_client, "client");
528 if (nfs4_ksp_server != NULL)
529 nfs4_read_kstat (nfs4_ksp_server, "server");
530 /* nfs_kstat(nfs3_ksp_client); */
531 #endif /* defined(HAVE_LIBKSTAT) */
533 return (0);
534 }
536 void module_register (void)
537 {
538 plugin_register_read ("nfs", nfs_read);
539 } /* void module_register */