9efe326c748a22efe9e7b574c0dbdc8e8cc3e096
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 #if HAVE_LIBKSTAT
129 static const char *nfs4_procedures_names[] =
130 {
131 "null",
132 "compound",
133 "reserved",
134 "access",
135 "close",
136 "commit",
137 "create",
138 "delegpurge",
139 "delegreturn",
140 "getattr",
141 "getfh",
142 "link",
143 "lock",
144 "lockt",
145 "locku",
146 "lookup",
147 "lookupp",
148 "nverify",
149 "open",
150 "openattr",
151 "open_confirm",
152 "open_downgrade",
153 "putfh",
154 "putpubfh",
155 "putrootfh",
156 "read",
157 "readdir",
158 "readlink",
159 "remove",
160 "rename",
161 "renew",
162 "restorefh",
163 "savefh",
164 "secinfo",
165 "setattr",
166 "setclientid",
167 "setclientid_confirm",
168 "verify",
169 "write",
170 NULL
171 };
172 static int nfs4_procedures_names_num = 39;
173 #endif
175 #if HAVE_LIBKSTAT
176 extern kstat_ctl_t *kc;
177 static kstat_t *nfs2_ksp_client;
178 static kstat_t *nfs2_ksp_server;
179 static kstat_t *nfs3_ksp_client;
180 static kstat_t *nfs3_ksp_server;
181 static kstat_t *nfs4_ksp_client;
182 static kstat_t *nfs4_ksp_server;
183 #endif
185 /* Possibly TODO: NFSv4 statistics */
187 #if HAVE_LIBKSTAT
188 static int nfs_init (void)
189 {
190 kstat_t *ksp_chain = NULL;
192 nfs2_ksp_client = NULL;
193 nfs2_ksp_server = NULL;
194 nfs3_ksp_client = NULL;
195 nfs3_ksp_server = NULL;
196 nfs4_ksp_client = NULL;
197 nfs4_ksp_server = NULL;
199 if (kc == NULL)
200 return (-1);
202 for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
203 ksp_chain = ksp_chain->ks_next)
204 {
205 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
206 continue;
207 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
208 nfs2_ksp_server = ksp_chain;
209 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
210 nfs3_ksp_server = ksp_chain;
211 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
212 nfs4_ksp_server = ksp_chain;
213 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
214 nfs2_ksp_client = ksp_chain;
215 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
216 nfs3_ksp_client = ksp_chain;
217 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
218 nfs4_ksp_client = ksp_chain;
219 }
221 return (0);
222 } /* int nfs_init */
223 #endif
225 #define BUFSIZE 1024
226 #if HAVE_LIBKSTAT
228 static void nfs2_procedures_submit(unsigned long long *val,
229 const char *plugin_instance, char *nfs_ver, int len)
230 {
231 value_t values[1];
232 value_list_t vl = VALUE_LIST_INIT;
233 char pl_instance[30];
234 int i;
236 vl.values = values;
237 vl.values_len = 1;
238 sstrncpy(vl.host, hostname_g, sizeof (vl.host));
239 sstrncpy(vl.plugin, "nfs", sizeof (vl.plugin));
240 sstrncpy(pl_instance, nfs_ver, strlen(nfs_ver) + 1);
241 strcat(pl_instance, plugin_instance);
242 sstrncpy(vl.plugin_instance, pl_instance,
243 sizeof (vl.plugin_instance));
244 sstrncpy(vl.type, "nfs_procedure", sizeof (vl.type));
247 for (i = 0; i < len; i++)
248 {
249 values[0].derive = val[i];
250 if (strcmp(nfs_ver, "nfs2") == 0)
251 sstrncpy(vl.type_instance, nfs2_procedures_names[i],
252 sizeof (vl.type_instance));
253 else if (strcmp(nfs_ver, "nfs3") == 0)
254 sstrncpy(vl.type_instance, nfs3_procedures_names[i],
255 sizeof (vl.type_instance));
256 else if (strcmp(nfs_ver, "nfs4") == 0) {
257 sstrncpy(vl.type_instance, nfs4_procedures_names[i],
258 sizeof (vl.type_instance));
259 }
261 DEBUG("%s-%s/nfs_procedure-%s = %lld",
262 vl.plugin, vl.plugin_instance,
263 vl.type_instance, val[i]);
264 plugin_dispatch_values (&vl);
265 }
266 }
267 #endif
269 static void nfs_procedures_submit (const char *plugin_instance,
270 unsigned long long *val, const char **names, int len)
271 {
273 value_t values[1];
274 value_list_t vl = VALUE_LIST_INIT;
275 int i;
277 vl.values = values;
278 vl.values_len = 1;
279 sstrncpy(vl.host, hostname_g, sizeof (vl.host));
280 sstrncpy(vl.plugin, "nfs", sizeof (vl.plugin));
281 sstrncpy(vl.plugin_instance, plugin_instance,
282 sizeof (vl.plugin_instance));
283 sstrncpy(vl.type, "nfs_procedure", sizeof (vl.type));
285 for (i = 0; (i < len); i++) {
286 values[0].derive = val[i];
287 sstrncpy(vl.type_instance, names[i],
288 sizeof (vl.type_instance));
289 DEBUG("%s-%s/nfs_procedure-%s = %llu",
290 vl.plugin, vl.plugin_instance,
291 vl.type_instance, val[i]);
292 plugin_dispatch_values(&vl);
293 }
294 } /* void nfs_procedures_submit */
296 static void nfs_read_stats_file (FILE *fh, char *inst)
297 {
298 char buffer[BUFSIZE];
300 char plugin_instance[DATA_MAX_NAME_LEN];
302 char *fields[48];
303 int numfields = 0;
305 if (fh == NULL)
306 return;
308 while (fgets (buffer, BUFSIZE, fh) != NULL)
309 {
310 numfields = strsplit (buffer, fields, 48);
312 if (((numfields - 2) != nfs2_procedures_names_num)
313 && ((numfields - 2)
314 != nfs3_procedures_names_num))
315 continue;
317 if (strcmp (fields[0], "proc2") == 0)
318 {
319 int i;
320 unsigned long long *values;
322 if ((numfields - 2) != nfs2_procedures_names_num)
323 {
324 WARNING ("nfs plugin: Wrong "
325 "number of fields (= %i) "
326 "for NFSv2 statistics.",
327 numfields - 2);
328 continue;
329 }
331 ssnprintf (plugin_instance, sizeof (plugin_instance),
332 "v2%s", inst);
334 values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
335 if (values == NULL)
336 {
337 char errbuf[1024];
338 ERROR ("nfs plugin: malloc "
339 "failed: %s",
340 sstrerror (errno, errbuf, sizeof (errbuf)));
341 continue;
342 }
344 for (i = 0; i < nfs2_procedures_names_num; i++)
345 values[i] = atoll (fields[i + 2]);
347 nfs_procedures_submit (plugin_instance, values,
348 nfs2_procedures_names,
349 nfs2_procedures_names_num);
351 free (values);
352 }
353 else if (strncmp (fields[0], "proc3", 5) == 0)
354 {
355 int i;
356 unsigned long long *values;
358 if ((numfields - 2) != nfs3_procedures_names_num)
359 {
360 WARNING ("nfs plugin: Wrong "
361 "number of fields (= %i) "
362 "for NFSv3 statistics.",
363 numfields - 2);
364 continue;
365 }
367 ssnprintf (plugin_instance, sizeof (plugin_instance),
368 "v3%s", inst);
370 values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
371 if (values == NULL)
372 {
373 char errbuf[1024];
374 ERROR ("nfs plugin: malloc "
375 "failed: %s",
376 sstrerror (errno, errbuf, sizeof (errbuf)));
377 continue;
378 }
380 for (i = 0; i < nfs3_procedures_names_num; i++)
381 values[i] = atoll (fields[i + 2]);
383 nfs_procedures_submit (plugin_instance, values,
384 nfs3_procedures_names,
385 nfs3_procedures_names_num);
387 free (values);
388 }
389 } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
390 } /* void nfs_read_stats_file */
391 #undef BUFSIZE
393 #if HAVE_LIBKSTAT
394 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
395 {
396 unsigned long long values[nfs2_procedures_names_num];
398 kstat_read(kc, ksp, NULL);
399 values[0] = get_kstat_value (ksp, "null");
400 values[1] = get_kstat_value (ksp, "getattr");
401 values[2] = get_kstat_value (ksp, "setattr");
402 values[3] = get_kstat_value (ksp, "root");
403 values[4] = get_kstat_value (ksp, "lookup");
404 values[5] = get_kstat_value (ksp, "readlink");
405 values[6] = get_kstat_value (ksp, "read");
406 values[7] = get_kstat_value (ksp, "wrcache");
407 values[8] = get_kstat_value (ksp, "write");
408 values[9] = get_kstat_value (ksp, "create");
409 values[10] = get_kstat_value (ksp, "remove");
410 values[11] = get_kstat_value (ksp, "rename");
411 values[12] = get_kstat_value (ksp, "link");
412 values[13] = get_kstat_value (ksp, "symlink");
413 values[14] = get_kstat_value (ksp, "mkdir");
414 values[15] = get_kstat_value (ksp, "rmdir");
415 values[16] = get_kstat_value (ksp, "readdir");
416 values[17] = get_kstat_value (ksp, "statfs");
418 nfs2_procedures_submit (values, inst, "nfs2", nfs2_procedures_names_num);
419 }
421 static void nfs3_read_kstat(kstat_t *ksp, char *inst)
422 {
423 unsigned long long values[nfs3_procedures_names_num];
425 kstat_read(kc, ksp, NULL);
426 values[0] = get_kstat_value (ksp, "null");
427 values[1] = get_kstat_value (ksp, "getattr");
428 values[2] = get_kstat_value (ksp, "setattr");
429 values[3] = get_kstat_value (ksp, "lookup");
430 values[4] = get_kstat_value (ksp, "access");
431 values[5] = get_kstat_value (ksp, "readlink");
432 values[6] = get_kstat_value (ksp, "read");
433 values[7] = get_kstat_value (ksp, "write");
434 values[8] = get_kstat_value (ksp, "create");
435 values[9] = get_kstat_value (ksp, "mkdir");
436 values[10] = get_kstat_value (ksp, "symlink");
437 values[11] = get_kstat_value (ksp, "mknod");
438 values[12] = get_kstat_value (ksp, "remove");
439 values[13] = get_kstat_value (ksp, "rmdir");
440 values[14] = get_kstat_value (ksp, "rename");
441 values[15] = get_kstat_value (ksp, "link");
442 values[16] = get_kstat_value (ksp, "readdir");
443 values[17] = get_kstat_value (ksp, "readdirplus");
444 values[18] = get_kstat_value (ksp, "fsstat");
445 values[19] = get_kstat_value (ksp, "fsinfo");
446 values[20] = get_kstat_value (ksp, "pathconf");
447 values[21] = get_kstat_value (ksp, "commit");
449 nfs2_procedures_submit (values, inst, "nfs3", nfs3_procedures_names_num);
450 }
452 static void nfs4_read_kstat(kstat_t *ksp, char *inst)
453 {
454 unsigned long long values[nfs4_procedures_names_num];
456 kstat_read(kc, ksp, NULL);
458 values[0] = get_kstat_value (ksp, "null");
459 values[1] = get_kstat_value (ksp, "compound");
460 values[2] = get_kstat_value (ksp, "reserved");
461 values[3] = get_kstat_value (ksp, "access");
462 values[4] = get_kstat_value (ksp, "close");
463 values[5] = get_kstat_value (ksp, "commit");
464 values[6] = get_kstat_value (ksp, "create");
465 values[7] = get_kstat_value (ksp, "delegpurge");
466 values[8] = get_kstat_value (ksp, "delegreturn");
467 values[9] = get_kstat_value (ksp, "getattr");
468 values[10] = get_kstat_value (ksp, "getfh");
469 values[11] = get_kstat_value (ksp, "link");
470 values[12] = get_kstat_value (ksp, "lock");
471 values[13] = get_kstat_value (ksp, "lockt");
472 values[14] = get_kstat_value (ksp, "locku");
473 values[15] = get_kstat_value (ksp, "lookup");
474 values[16] = get_kstat_value (ksp, "lookupp");
475 values[17] = get_kstat_value (ksp, "nverify");
476 values[18] = get_kstat_value (ksp, "open");
477 values[19] = get_kstat_value (ksp, "openattr");
478 values[20] = get_kstat_value (ksp, "open_confirm");
479 values[21] = get_kstat_value (ksp, "open_downgrade");
480 values[22] = get_kstat_value (ksp, "putfh");
481 values[23] = get_kstat_value (ksp, "putpubfh");
482 values[24] = get_kstat_value (ksp, "putrootfh");
483 values[25] = get_kstat_value (ksp, "read");
484 values[26] = get_kstat_value (ksp, "readdir");
485 values[27] = get_kstat_value (ksp, "readlink");
486 values[28] = get_kstat_value (ksp, "remove");
487 values[29] = get_kstat_value (ksp, "rename");
488 values[30] = get_kstat_value (ksp, "renew");
489 values[31] = get_kstat_value (ksp, "restorefh");
490 values[32] = get_kstat_value (ksp, "savefh");
491 values[33] = get_kstat_value (ksp, "secinfo");
492 values[34] = get_kstat_value (ksp, "setattr");
493 values[35] = get_kstat_value (ksp, "setclientid");
494 values[36] = get_kstat_value (ksp, "setclientid_confirm");
495 values[37] = get_kstat_value (ksp, "verify");
496 values[38] = get_kstat_value (ksp, "write");
498 nfs2_procedures_submit (values, inst, "nfs4", nfs4_procedures_names_num);
499 }
500 #endif
502 static int nfs_read (void)
503 {
504 FILE *fh;
506 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
507 {
508 nfs_read_stats_file (fh, "client");
509 fclose (fh);
510 }
512 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
513 {
514 nfs_read_stats_file (fh, "server");
515 fclose (fh);
516 }
518 #if HAVE_LIBKSTAT
519 nfs_init ();
520 if (nfs2_ksp_client != NULL)
521 nfs2_read_kstat (nfs2_ksp_client, "client");
522 if (nfs2_ksp_server != NULL)
523 nfs2_read_kstat (nfs2_ksp_server, "server");
524 if (nfs3_ksp_client != NULL)
525 nfs3_read_kstat (nfs3_ksp_client, "client");
526 if (nfs3_ksp_server != NULL)
527 nfs3_read_kstat (nfs3_ksp_server, "server");
528 if (nfs4_ksp_client != NULL)
529 nfs4_read_kstat (nfs4_ksp_client, "client");
530 if (nfs4_ksp_server != NULL)
531 nfs4_read_kstat (nfs4_ksp_server, "server");
532 /* nfs_kstat(nfs3_ksp_client); */
533 #endif /* defined(HAVE_LIBKSTAT) */
535 return (0);
536 }
538 void module_register (void)
539 {
540 plugin_register_read ("nfs", nfs_read);
541 } /* void module_register */